在C#中定义了关键字sealed,被sealed修饰的类不能够被继承。在Java中同样也有关键字final表示一个类不能被继承。C++11提供final关键字使得类不能够被继承。
那么,如何自己实现一个不被继承的类?常规的解法是,把类的构造和析构函数都设置为private即可,然后公有派生;这是因为子类访问不到父类私有属性。这使用了C++构造派生类实例时会自动先调用父类构造函数的特性,同样析构的顺序和构造的顺序相反。
这种做法可行,但是我们只能得到位于栈上或堆上的实例(通过类内的static方法创建实例)!如果在堆和栈都能创建实例呢?且看下面的描述:
如果一个类D虚拟继承父类B,那么类D的派生类的实例被创建时会跳过类B的构造函数,直接调用类D的构造函数。根据这一特点,我们可以把D的构造函数和析构函数都设置为private,即可实现类D不能被继承!
但D公有继承自类B,那么D的构造函数和析构函数会分别调用父类B的构造和析构函数,而此时父类B的构造和析构函数均为private,如何使得派生类D拥有父类B私有成员的访问权限呢?
使用友元和模板!!!!完整代码如下,代码中的注释说明了一起!
template<class T>
class MakeSealed
{
friend T;// ① 友元类,使得友元T拥有访问private成员的权限
private:// ② 把类的构造函数和析构函数为private,那么该类不能够被继承!!!
// 因为它的派生类不具有访问私有构造函数和析构函数的权限;但是假如派生类是该父类的友元,那么该类便可派生!
MakeSealed() {
std::cout << "MakeSealed ctor called!" << std::endl;
}
~MakeSealed() {
std::cout << "MakeSealed dtor called!" << std::endl;
}
};
// SealedClass为MakeSealed父类的友元,否则SealedClass的构造函数和析构函数因不可访问父类构造和析构函数而提示错误!
class SealedClass : virtual/* ③ 不能被派生的SealedClass必须虚继承MakeSealed */ public MakeSealed<SealedClass>
{
public:
SealedClass() {
std::cout << "SealedClass ctor called!" << std::endl;
}
~SealedClass() {
std::cout << "SealedClass dtor called!" << std::endl;
}
};
class Try : public SealedClass
{
public:
Try() {// VS2015提示错误:“MakeSealed::MakeSealed()[其中T=SealedClass]不可访问”
std::cout << "Try ctor called!" << std::endl;
}
~Try() {// VS2015提示错误:“MakeSealed::~MakeSealed()[其中T=SealedClass]不可访问”
std::cout << "Try ctor called!" << std::endl;
}
};