题目来自剑指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(){}
};