C++中如何实现final类

本文介绍了两种在C++中防止一个类被继承的方法:一是将构造函数设为私有并提供静态工厂方法;二是利用虚继承和友元类机制。深入探讨了这两种方法的工作原理及其优缺点。
 

在Java中,如果用final修饰变量,则相当于c++中的const。但是final还可以修饰类和函数。当用来修饰类时,则表示类不能被继承, 而c++语言本身就没有这方面的功能。下面我会先给出解决方案,然后就其内部原理等展开进一步的讨论。因为水平有限,难免有错,还请大家指正。

方法一, 将构造函数声明为private

class NoDerivable

{

private:

NoDerivable();

... ...

public:

static NoDerivable* Create();

... ...

};


class   TestClass   :   public   NonDerivable
{
TestClass(){};//编译无法通过
//...
};

这是最简单的方法,但缺点是不能用new来直接创建类的实例,必须添加一个工厂方法,通过该方法来创建类的实例。


方法二,利用虚继承

class   NonDerivableBase
{

private:

NonDerivableBase(){}
friend   class   NonDerivable;
};

#define   FINAL_CLASS   :   private   virtual   NonDerivableBase


class   NonDerivable   FINAL_CLASS
{
//...   some   code   here
};

class  TestClass   :   public   NonDerivable
{

TestClass(){};//编译无法通过
//...
}; 

首先,必须对NonDerivableBase是虚继承, 是否是private不重要。这种方法的问题是,必须为每个final 类定义一个base类。不过我们可以利用模板技术来进行改进。具体实现如下:

最终解决方案:

template<typename T>

class   NonDerivableBase
{

private:

NonDerivableBase(){}
friend   class   T;
};

#define   FINAL_CLASS (T)  :   private   virtual   NonDerivableBase<T>


class   NonDerivable   FINAL_CLASS(NonDerivable)
{
//... ...

};

class   TestClass   :   public   NonDerivable
{
TestClass(){};//编译无法通过
//...
};

个人认为这是最完整的解决方案,如果谁还有更好的建议,欢迎讨论。


进一步讨论:

问题一,为什么是虚继承?

大家肯定会注意到,上面的方法用到了虚继承。那不用虚继承是否可以呢?答案当然是不可以,这个大家可以自己去试。为什么呢?如果你对C++的内存对象模型有所了解的话,应该比较容易理解。下面简单说一下。

如果是普通继承,父类对象(通常称为subobject)是包含在子类对象中的,所以构造函数的调用也是TestClass的构造函数调用NonDerivable的构造函数,再由NonDerivable调用NonDerivableBase的构造函数,以上调用都不存在访问权限的问题,也就不能防止NonDerivable被继承。

而对于虚继承,需要确保最上层的类被实例化一次,因此当构造一个子类(TestClass)对象时,会先在内存中生成一个最上层类(NonDerivableBase)的对象,而TestClass 无权访问NonDerivableBase的private的构造函数,因此会编译不过。


问题二,为什么一定要用友元?

用友元是为了让NonDerivable自己能够实例化。我还在网上看到有一个不用友元的方法:

namespace   Private 

class   NonDerivableBase

public: 
    //NonDerivableBase(){} 
    NonDerivableBase(int){}//ADDED   CTOR   ARGUMENT 
}; 

#define   FINAL_CLASS   :   private   virtual   Private::NonDerivableBase 


class   NonDerivable   FINAL_CLASS 

public: 
NonDerivable()   :   NonDerivableBase(0)   {}   //PASS   A   DUMMY   VALUE 
}; 

实际上,这个方法是有问题的。因为我们可以这样来实现子类

class TestClass : public NonDerivable, private virtual Private::NonDerivableBase

 {                                             
public:                                       
     TestClass(): NonDerivableBase(0) {};
};




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值