C++实现不能被继承的类

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();//只能以这样的方式实例化一个对象;




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值