题目来自剑指Offer
使用C++设计一个不能被继承的类,
方法:把构造函数和析构函数设置为私有函数 + 新增俩方法创建对象和销毁对象
原因:
(1)把构造函数和析构函数设置为私有函数 :防止子类调用构造函数函数和析构函数,防止继承
(2)新增俩方法创建对象和销毁对象:为了不影响自己创建和销毁对象,就通过静态方法创建和销毁对象。
代码:
class SealClass { public: static SealClass* GetInstance(); static void DelInstance(SealClass* pS); private: SealClass(){} ~SealClass(){} }; SealClass* SealClass::GetInstance() { cout<<"Create an Instance"<<endl; return new SealClass(); } void SealClass::DelInstance(SealClass* pS) { delete pS; cout<<"Del an Instance"<<endl; }
会影响类SealClass对象的创建,该方法只能创建堆上的对象,不能创建栈上的对象。
测试代码:
#include <iostream> #include <assert.h> using namespace std; class SealClass { public: static SealClass* GetInstance(int nData); static void DelInstance(SealClass* pS); private: SealClass(){} SealClass(int nData); ~SealClass(){} private: int m_nData; }; class Drived : public SealClass { public: Drived(){} ~Drived(){} }; SealClass* SealClass::GetInstance(int nData) { cout<<"Create an Instance"<<endl; return new SealClass(nData); } void SealClass::DelInstance(SealClass* pS) { delete pS; cout<<"Del an Instance"<<endl; } SealClass::SealClass(int nData) { m_nData = nData; } int main() { /*创建自己的对象*/ SealClass* pS = SealClass::GetInstance(1); SealClass::DelInstance(pS); //SealClass s;//错误 /*创建子类*/ //Drived d;//错误 //Drived* pD = new Drived;//错误 system("pause"); return 1; }
(1)静态成员:在类中有Static修饰,在类外没有Static修饰。
(2)静态成员是属于类级别的,调用时可以直接使用类::成员调用
(2)非静态成员是不能使用类::成员的方式调用的。
方法:虚基类 + 虚基类构造函数和析构函数私有化 + 不能派生类SealClass变成基类友元类
(1)另外设置一个基类Base
(2)把基类Base的构造函数和析构函数设置为私有。
(3)把要设置SealClass类变成基类的友元类
(4)SealClass类虚拟继承Base。
原因:
(1)把基类Base的构造函数和析构函数私有化:目的是为了防止让其他类从基类Base中派生,当然此时该类也不能定义对象。
(2)由于要设置SealClass类为基类Base的友元类:根据友元的性质,则该类可以自由访问基类Base中的成员,即可以该类可以不受限制的访问基类Base的构造函数和析构函数。
(3)基类的友员不能被派生类继承的:此时之后创建的Derive就不能使用父类的友元了
(4)为什么是虚继承?
主要原因:如果是虚继承的话,假设类Derive要从SealClass继承,由于是虚继承,该派生类Derive会直接调用虚基类Base的构造函数,而不会通过基类SealClass,此时就会报错。
虚继承的附带优点:如果有一个类也不想被继承,且也从Base继承,且该类与SealClass具有层次关系,如果不设计为虚继承,就会出现二义性。
(1)一定要设置为虚继承:如果不是虚继承的话,类Derive的对象会调用父类的构造函数,而且父类SealClass可以调用Base的构造函数和析构函数,则此时是可以有类从SealClass继承的。
(2)在有虚继承的情况下,派生类先调用虚基类的构造函数,再调用非虚基类的构造函数。虚基类的子对象在整个初始化过程中只调用一次。
有些编译器对虚基类支持不好,不易扩展。
class Base { public: friend SealClass; private: Base(){} ~Base(){} }; class SealClass : virtual public Base { public: SealClass(){} ~SealClass(){} };
测试代码:
#include <iostream> #include <assert.h> using namespace std; class SealClass; class Base { public: friend SealClass; private: Base(){} ~Base(){} }; class SealClass : virtual public Base { public: SealClass(){} ~SealClass(){} }; //class Drived : public SealClass //{ //public: // Drived(){} // ~Drived(){} //}; int main() { /*创建自己的对象*/ SealClass* pS = new SealClass; delete pS; SealClass s;//错误 /*创建子类*/ //Drived d;//错误 //Drived* pD = new Drived;//错误 system("pause"); return 1; }
原因:只有想让某个类不能派生对象,就可以从该类继承。
template<typename T> class Base { public: friend T; private: Base(){} ~Base(){} }; class SealClass : virtual public Base<SealClass> { public: SealClass(){} ~SealClass(){} };