C++ 设计一个不能被继承的类
来源:互联网 发布:淘宝卖家的需求分析 编辑:程序博客网 时间:2024/05/16 16:20
吃饭时与“大姐”讨论问题,他问道“C++如何设计一个不能被继承的类”?不能被继承,那把构造函数和析构函数设计成私有的不就行了,这样一来子类不能访问父类的构造函数和析构函数,也就无法继承了。然而这样一来,这个类在其他地方也就不能实例化了,没有存在的意义了。
这时候你是不是想到了静态方法,是啊,我们可以通过静态方法来返回类的实例,然后通过另一个静态方法来释放该类对象。代码如下:
//static functionclass A{public: static A* getInstance(int n) { A* pa = new A(); pa->num = n; return pa; } static void destructInstance(A* pInstance) { delete pInstance; pInstance = NULL; }private: A(){cout << "construct A" << endl;} ~A(){cout << "destruct A" << endl;}public: int num;};
你可能会问,为什么必须返回指针而不返回对象的引用呢?这里必须返回指针,而不能像如下代码一样返回引用:
class AR{public: static AR& getInstance(int n) { AR par; par.num = n; return par; } static void destructInstance(AR& pInstance) { pInstance.~AR(); }private: AR(){cout << "construct AR" << endl;} ~AR() { cout << "destruct AR" << endl; }public: int num;};
我写了一段测试代码,来测试返回指针和返回引用时的效果:
void testStatic(){ cout << "---------------A: return pointer-------------" << endl; A *sa = A::getInstance(9); cout << "num is: " << sa->num << endl; A::destructInstance(sa); cout << "-------------AR: return reference------------" << endl; AR &ra = AR::getInstance(9); cout << "num is: " << ra.num << endl; AR::destructInstance(ra);}
输出如下:
可以看到,当返回引用时,在输出num之前,对象就已经被析构了。因为在static AR& getInstance()函数中声明的对象AR par是局部变量,当函数运行完,该变量就会被释放掉,而返回的却是已经被释放掉的对象的引用,这无疑会造成内存泄漏。所以,只能通过new来动态申请堆上的内存,然后返回指针,而不能返回引用。
可是这样一来,类A虽然不能被继承,但却只能在堆上创建对象,而不能在栈上创建对象。要知道很多时候,我们只想创建一个临时对象,使用栈空间会更高效方便一些。(关于栈空间和堆空间,这里有一篇不错的博文http://www.cnblogs.com/kevinGaoblog/archive/2012/03/23/2413102.html)如何才能使我们的类既不能被继承,又能够在堆和栈上都可以创建对象呢?
考虑一下友元,友元可以访问类的私有成员,因此,我们可以创建一个基类,使其构造函数和析构函数为私有成员,然后让我们设计的非继承类成为基类的友元,这样一来,问题不就解决了。看下代码:
template <typename T>class Base{ friend T; // 这种写法好像是C++11才支持的private: Base(){cout << "construct Base" << endl;} ~Base(){cout << "destruct Base" << endl;}};class finalClass: virtual public Base<finalClass>{public: finalClass():num(0) { cout << "construct finalClass" << endl; } finalClass(int n):num(n) { cout << "construct finalClass" << endl; } ~finalClass(){cout << "destruct finalClass" << endl;} int num;};void testFriend(){ cout << "--------------object on heap-----------------" << endl; finalClass *pfc = new finalClass(9); // 堆上的对象 cout << "num is: " << pfc->num << endl; delete pfc; cout << "-------------Object on stack-----------------" << endl; finalClass fc(9); // 栈上的对象 cout << "num is: " << fc.num << endl;}// testclass derivedClass: public finalClass{public: derivedClass(){cout << "construct derivedClass" << endl;} ~derivedClass(){cout << "destruct derivedClass" << endl;}};
其中testFriend()的输出如下:
无论在堆上创建对象还是在栈上创建对象都没有问题。这里需要说明的是,finalClass对Base的继承必须是虚继承,这样一来当derivedClass继承finalClass时就会去直接调用Base的构造函数,但由于Base的构造函数是私有的,而derivedClass不是Base的友元,因此会报出编译错误。于是,我们设计的类finalClass就是一个完整的不能被继承的类。
如果不是虚继承的话,derivedClass不会直接调用基类的构造函数,它只会调用父类finalClass的构造函数,而finalClass在构造时调用基类Base的构造函数是没有任何问题的。关于单一继承、多重继承与虚继承,推荐博文http://blog.csdn.net/haoel/article/details/3081328 , http://blog.chinaunix.net/uid-16723279-id-3568748.html。
另外需要说明的是,友元关系不具有传递性。finalClass是Base的友元,即使derivedClass继承了finalClass, derivedClass也不是Base的友元。即:友元关系不能继承,基类的友元对派生类的成员没有访问权限,如果基类被授予友元关系,则只有基类具有特殊访问权限,该基类的派生类不能访问授予友元关系的类。
现在,C++11中已经像java一样有了final关键字,被final关键字修饰的虚函数(只能是虚函数)不能被重载,被final修饰的类不能被继承。
struct Base{ virtual void foo();};struct A : Base{ virtual void foo() final; // A::foo is final void bar() final; // Error: non-virtual function cannot be final};struct B final : A // struct B is final{ void foo(); // Error: foo cannot be overridden as it's final in A};struct C : B // Error: B is final{};
- 设计一个不能被继承的类
- 设计一个不能被继承的类
- 设计一个不能被继承的类
- 设计一个不能被继承的类
- 设计一个不能被继承的类
- 设计一个不能被继承的类
- 设计一个不能被继承的类
- 设计一个不能被继承的类
- 设计一个不能被继承的类
- 用C++设计一个不能被继承的类
- 用C++设计一个不能被继承的类
- 用C++ 设计一个不能被继承的类
- [转]用C++ 设计一个不能被继承的类
- 用C++设计一个不能被继承的类
- 用C++设计一个不能被继承的类
- 用C++ 设计一个不能被继承的类。
- 用 C++ 设计一个不能被继承的类
- 用C++设计一个不能被继承的类
- iOS进阶之UI利器Reveal(1)--Reveal的下载,安装和破解
- 批处理学习,持续更新。。。
- IBM发明世界首个人造神经元,人工智能的底层硬件基石已完成!
- JMeter学习(八)JDBC测试计划-连接Oracle
- hdu 5802——Windows 10
- C++ 设计一个不能被继承的类
- Ubuntu桌面
- Win7系统安装MySQL5.5.21图解教程大家都知道MySQL是一款中、小型关系型数据库管理系统,很具有实用性
- ping 过程中发生了什么?
- (23)函数概念 (24)函数定义格式和命名规范 (25) 函数执行与返回流程 (26)函数传参方式
- Qt---QFtp上传、下载二进制文件
- Snackbar
- [又值奥运季] 2016年里约奥运会--8月9日赛事
- 调用存储过程