学习过Java和c#的童鞋应该都知道,在Java中定义了关键字final表示一个类不能被继承,在C#中也有相同意义的关键字sealed表示一个类不能被继承,那仫在C++中呢?在C++11之前是没有的类似这样的关键字的,只能自己实现了。(在C++11中该关键字已经被加入到C++中,这个关键字的作用就是阻止类的进一步派生和虚函数的进一步重载)。
如何在C++中定义一个不能被继承的类呢?
想法一:私有构造函数来解决
我们都知道在C++中子类的构造函数会自动调用父类的构造函数,子类的析构函数也会自动调用父类的析构函数。如果想要一个类无法被继承,那仫这个类的构造函数和析构函数必须是私有的,但是这样又会出现新的问题?就是这个类的构造函数和析构函数是私有的,我们如何获取和删除这个类的实例化对象呢?共有的静态函数就可以解决这个问题。
class Base
{
public:
//编写静态函数来创建和释放类的实例化
static Base *GetSpace()
{
cout<<"GetSpace()"<<endl;
return new Base();
}
static void DeleteSpace(Base *del)
{
cout<<"DeleteSpace()"<<endl;
delete del;
}
private:
//私有化构造和析构函数
Base()
{}
~Base()
{}
};
int main()
{
//静态成员函数没有隐含this指针参数,使用类型::作用域访问符直接调用静态成员函数
Base *b=Base::GetSpace();
Base::DeleteSpace(b);
system("pause");
return 0;
}
这样的实现会不会存在什仫问题呢?通过观察上面的代码我发现实例化一个对象只能使用new来实例,也就是说这个新创建的对象只能在堆上生成,这就存在一定的局限性。那仫如何解决呢?
想法二:利用虚拟继承的方法
同样是将父类的构造函数私有化,但是却定义了一个模板类型的友元,因为友元的特性:如果一个类是另一个类的友元,友元类的每个成员函数都是另一个类的友元函数,都可访问另一个类中的保护或私有数据成员。我们在子类中调用父类的构造和析构函数是不会出错的。
这种想法比方法一的想法好的一点就是:既可以在堆上实例化对象也可以在栈上实例化对象。
template<typename T>
class Base
{
friend T; //定义友元,子类可以访问父类的私有成员对象
private:
Base()
{
cout<<"Base()"<<endl;
}
~Base()
{
cout<<"~Base()"<<endl;
}
};
//虚继承
class Sub:virtual public Base<Sub>
{
public:
Sub()
{
cout<<"Sub()"<<endl;
}
~Sub()
{
cout<<"~Sub()"<<endl;
}
};
int main()
{
Sub s1; //可以在栈上开辟
Sub *s2=new Sub; //可以在堆上开辟
delete s2;
system("pause");
return 0;
}
如果此时对Sub进行继承并对继承Sub的类进行实例化的时候是无法编译通过的。因为Sub是虚拟继承,所以当调用Test的构造函数的时候,会跳过Sub而直接调用Base的构造函数,又因为Base的构造函数是私有的且Test并不是Base的友元所以是不能调用的。
所以Sub就是满足题意的不能被继承的类。
class Test:public Sub
{
public:
Test()
{
cout<<"Test()"<<endl;
}
~Test()
{
cout<<"~Test()"<<endl;
}
};
当然了在C++中定义不能被继承的类有许多其他的方法,在这里我就只介绍这两种啦!!!