C++ 设计NVI(Non-Virtual Interface)

举报
用户已注销 发表于 2022/06/10 23:56:13 2022/06/10
【摘要】 目录 RAII(Resource Acquisition Is Initialization) ScopeGuard NVI(Non-Virtual Interface) CRTP(Curiously Recurring Template Pattern) PIMPL(Private Implementation) ...

目录

RAII(Resource Acquisition Is Initialization)

ScopeGuard

NVI(Non-Virtual Interface)

CRTP(Curiously Recurring Template Pattern)

PIMPL(Private Implementation)


RAII(Resource Acquisition Is Initialization)

即资源获取就是初始化,是一种管理资源的机制。

如管理new操作符的资源:


  
  1. class A
  2. {
  3. public:
  4. int *p;
  5. A(int n)
  6. {
  7. p = new int[n];
  8. }
  9. ~A()
  10. {
  11. delete p;
  12. }
  13. };
  14. int main()
  15. {
  16. A a(10);
  17. // a.p
  18. return 0;
  19. }

只写了一个简单的示例。

一个经典的案例:lock_guard类,源代码如下


  
  1. // CLASS TEMPLATE lock_guard
  2. template<class _Mutex>
  3. class lock_guard
  4. { // class with destructor that unlocks a mutex
  5. public:
  6. using mutex_type = _Mutex;
  7. explicit lock_guard(_Mutex& _Mtx)
  8. : _MyMutex(_Mtx)
  9. { // construct and lock
  10. _MyMutex.lock();
  11. }
  12. lock_guard(_Mutex& _Mtx, adopt_lock_t)
  13. : _MyMutex(_Mtx)
  14. { // construct but don't lock
  15. }
  16. ~lock_guard() noexcept
  17. { // unlock
  18. _MyMutex.unlock();
  19. }
  20. lock_guard(const lock_guard&) = delete;
  21. lock_guard& operator=(const lock_guard&) = delete;
  22. private:
  23. _Mutex& _MyMutex;
  24. };

实例化的时候加锁,生命周期结束的时候自动解锁。

ScopeGuard

这个方法是定义一个ScopeGuard模板类,用于管理临时使用的资源。

把临时资源的释放操作写成lambda表达式,申请ScopeGuard实例存放这个表达式,实例生命周期结束时自动

代码:


  
  1. template <typename Lambda>
  2. class ScopeGuard
  3. {
  4. public:
  5. ScopeGuard(Lambda &&lam): lambda (lam) {
  6. }
  7. ~ScopeGuard() {
  8. lambda();
  9. }
  10. private:
  11. Lambda lambda;
  12. };
  13. template <typename T>
  14. ScopeGuard<T> GetScopeGuard(T &&lambda)
  15. {
  16. return ScopeGuard<T>(move(lambda));
  17. }
  18. int main()
  19. {
  20. int* p = new int[100];
  21. GetScopeGuard([&] {delete[] p; });
  22. return 0;
  23. }

NVI(Non-Virtual Interface)

NVI是用非虚函数调用虚函数,把非虚函数作为接口。


  
  1. class A
  2. {
  3. public:
  4. void show()
  5. {
  6. cout << "A\n";
  7. print();
  8. }
  9. virtual void print() {};
  10. };
  11. class B :public A
  12. {
  13. public:
  14. void print()
  15. {
  16. cout << "x=" << x;
  17. }
  18. private:
  19. int x;
  20. };
  21. int main()
  22. {
  23. B b;
  24. b.show();
  25. return 0;
  26. }

CRTP(Curiously Recurring Template Pattern)

奇异的递归模板模式,指的是子类继承一个模板类,模板的特化类型是子类本身。

最简代码:


  
  1. #include<iostream>
  2. using namespace std;
  3. template<typename T>
  4. class Base
  5. {
  6. public:
  7. void virtualFunc()
  8. {
  9. static_cast<T*>(this)->realFunc();
  10. }
  11. };
  12. class Chird :public Base<Chird>
  13. {
  14. public:
  15. void realFunc()
  16. {
  17. cout << "real func";
  18. }
  19. };
  20. int main()
  21. {
  22. Chird().virtualFunc();
  23. return 0;
  24. }

这个简单的例子就能看出CRTP的写法,也能看出,其实本质上静态多态。

CRTP的好处是,静态多态比继承虚函数的动态多态要快。

应用:

CRTP单例模板

CRTP + 模板方法模式

PIMPL(Private Implementation)

通过一个私有的成员指针,将指针所指向的类的内部实现全部隐藏。

普通代码:


  
  1. class A
  2. {
  3. public:
  4. int f(int n)
  5. {
  6. return f1(n) + n + f2(n);
  7. }
  8. private:
  9. int f1(int n)
  10. {
  11. return n * n * n;
  12. }
  13. int f2(int n)
  14. {
  15. return n > 0 ? 1 : -1;
  16. }
  17. };

PIMPL代码:


  
  1. class B;
  2. class A
  3. {
  4. public:
  5. A()
  6. {
  7. opt = new B();
  8. }
  9. int f(int n)
  10. {
  11. return opt->f1(n) + n + opt->f2(n);
  12. }
  13. private:
  14. B* opt;
  15. };
  16. class B
  17. {
  18. public:
  19. int f1(int n)
  20. {
  21. return n * n * n;
  22. }
  23. int f2(int n)
  24. {
  25. return n > 0 ? 1 : -1;
  26. }
  27. };

文章来源: blog.csdn.net,作者:csuzhucong,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/nameofcsdn/article/details/125222648

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。