C++实现不能被继承的类
前一段时间面试被问到一个问题,如何实现一个不能被继承的类?
....*&*>>.<<*&*....
被问得一脸蒙蔽 :)Sadface,赶紧回来查了查资料,今天复习又想起来了,就记录一下
注:以下程序均在VS2013下测试通过!
实现方法一:虚继承+友元+模板
如下代码:
template<typename T>
class UnRetrivedBasedClass //基础类,实现不能被继承的类的基础;
{
friend T;
private:
UnRetrivedBasedClass(){
string str = typeid(T).name();
}
~UnRetrivedBasedClass(){}
};
class UnRetrived :virtual public UnRetrivedBasedClass<UnRetrived> //定义一个无法被继承的类UnRetrived;
{
public:
<span style="white-space:pre"> </span>UnRetrived(){}
<span style="white-space:pre"> </span>~UnRetrived(){}
};
class TestRetrived :public UnRetrived//试图继承一个无法被继承的类UnRetrived,失败;
{
public:
TestRetrived(){}
~TestRetrived(){}
};
int main(void){
<span style="white-space:pre"> </span>UnRetrived<span style="white-space:pre"> </span>a;<span style="white-space:pre"> </span>//实例化成功;
<span style="white-space:pre"> </span>TestRetrived<span style="white-space:pre"> </span>b;<span style="white-space:pre"> </span>//实例化失败!<pre name="code" class="cpp">}
下图是程序编译期间的错误,可知由于UnRetrivedBasedClass的构造函数为一个私有函数,TestRetrived无法访问该构造函数,从而无法编译通过!
分析:
1)虚继承:决定了构造函数的调用顺序,虚继承的类首先进行构造,按照深度优先、先左后右的顺序进行;
2)友元类:友元类(如上例中的模板类T、T的实现类UnRetrived)中任何一个函数均是另一个类(如上例中UnRetrivedBasedClass)的友元函数,可访问该类(如上例中UnRetrivedBasedClass)中所有的成员函数、成员元素(public/protected/private均可);
3)模板:将类(UnRetrived)的友元细节隔离,实现封装,从而模块化,达到可复用目的!
虚继承:
1)普通继承中的构造顺序——穿脱原则
对于非虚继承的public/protected/privated而言,构造顺序和解构顺序满足穿脱原则,即构造时父类先子类后,如同穿衣服先穿内衣再穿外套,解构时子类先父类后
构造顺序:父类构造列表->父类构造函数->子类构造列表->子类构造函数
解构顺序:子类解构函数->父类解构函数
2)虚继承中的构造顺序——虚继承优先
对于继承关系中存在虚继承的情况而言,优先虚继承然后普通继承,虚继承构造中深度优先、按照继承顺序中先左后右
TestRetrived试图集成一个不能被继承的类UnRetrivedBasedClass的构造顺序为:
1)调用TestRetrived构造函数TestRetrived::TestRetrived(),发现存在虚继承关系
2)调用UnRetrivedBasedClass模板类的构造函数UnRetrivedBasedClass::UnRetrivedBasedClass()
3)由于构造函数UnRetrivedBasedClass::UnRetrivedBasedClass()为私有函数,无法在TestRetrived::TestRetrived()中访问,退出,构造失败!
如果将UnRetrived对UnRetrivedBasedClass的继承方式由虚公共继承改变为公共继承,则无法完成实现一个不能被集成类的要求,其构造顺序为:
class UnRetrived :public UnRetrivedBasedClass < UnRetrived >
{
...
}
1)调用TestRetrived构造函数TestRetrived::TestRetrived()
2)调用子类UnRetrived构造函数UnRetrived::UnRetrived()
3)调用子类UnRetrivedBasedClass构造函数UnRetrivedBasedClass::UnRetrivedBasedClass(),虽然构造函数为私有函数,但由于UnRetrived为其友元,故而UnRetrived构造函数UnRetrived::UnRetrived()是子类UnRetrivedBasedClass的友元函数,可以访问其所有函数(包含私有函数、私有变量),完成UnRetrivedBasedClass的初始化列表、初始化构造函数,退出
4)完成UnRetrived的初始化列表、初始化构造函数,退出
5)完成TestRetrived的初始化列表、初始化构造函数,退出,完成构造
从而我们发现虚继承+友元是实现一个不能被继承类的必须,而模板则是一个可选项!
实现方法二:私有构造函数+单独实例化函数
class UnRetrived{
public:
static UnRetrived* getInstance(void){
return new UnRetrived;
}
void releaseInstance(UnRetrived* ptr){
delete ptr;
}
private:
UnRetrived(){}
~UnRetrived(){}
};
实例化该类时,使用如下代码,该方法无法向正常类一样实例化一个对象(A a;):
UnRetrived2* pTr = UnRetrived2::getInstance();//只能以这样的方式实例化一个对象;