昨天有人问我这个问题,在java中这不是个问题,因为有final关键字,而C++11中也有final关键字。
比如 class finalClass final { };
但C++11之前呢,如何实现?
首先想到的是可以将构造函数声明为private的,这样是可以阻止被别人继承,但这个类用起来也是很不方便,只能通过static成员函数来得到一个对象指针。
如果要在栈上定义一个对象都做不到,太麻烦了。
网上有一种方法是用virtual inheritance来实现,先看看示例代码:
$ cat final_class.cpp
#include <iostream>
using namespace std;
template <typename T>
class Helper
{
friend T;
private:
Helper() {cout<<"Helper::Helper\n";}
~Helper(){cout<<"Helper::~Helper\n";}
};
class finalClass : virtual public Helper<finalClass>
{
public:
finalClass(){cout<<"finalClass::finalClass\n";}
~finalClass(){cout<<"finalClass::~finalClass\n";}
};
class Derivation: public finalClass
{
public:
Derivation(){cout<<"Derivation::Derivation\n";}
~Derivation(){cout<<"Derivation::~Derivation\n";}
};
int main(int argc, char* argv[])
{
//Helper<int> a;
finalClass b;
Derivation c;
return 0;
}
Derivation类试图继承finalClass,结果编译报错(在ubuntu上):
$ g++ final_class.cpp -std=c++11; ./a.out
final_class.cpp: In constructor ‘Derivation::Derivation()’:
final_class.cpp:9:5: error: ‘Helper<T>::Helper() [with T = finalClass]’ is private
Helper() {cout<<"Helper::Helper\n";}
^
final_class.cpp:23:21: error: within this context
Derivation(){cout<<"Derivation::Derivation\n";}
^
final_class.cpp:10:5: error: ‘Helper<T>::~Helper() [with T = finalClass]’ is private
~Helper(){cout<<"Helper::~Helper\n";}
^
final_class.cpp:23:21: error: within this context
Derivation(){cout<<"Derivation::Derivation\n";}
^
final_class.cpp: In destructor ‘Derivation::~Derivation()’:
final_class.cpp:10:5: error: ‘Helper<T>::~Helper() [with T = finalClass]’ is private
~Helper(){cout<<"Helper::~Helper\n";}
^
final_class.cpp:24:22: error: within this context
~Derivation(){cout<<"Derivation::~Derivation\n";}
-----------------------------------------
如果finalClass类不是虚继承自Helper类(即将关键字virutal去掉),那它还是能被Derivation类继承。
因此编译能通过,结果是:
$ g++ final_class.cpp -std=c++11; ./a.out
Helper::Helper
finalClass::finalClass
Helper::Helper
finalClass::finalClass
Derivation::Derivation
Derivation::~Derivation
finalClass::~finalClass
Helper::~Helper
finalClass::~finalClass
Helper::~Helper
为什么这里finalClass类虚继承自Helper后,它就不能被Derivation类继承了呢?
落脚点在虚继承的实现上。
首先虚继承是为了解决多重继承中,出现菱形状的继承关系时,比如:
Base
/ \
D1 D2
\ /
TopDiamond
struct Base {};
struct D1: Base {};
struct D2: Base {};
struct TopDiamond: D1, D2 {};
TopDiamond对象中会有两个Base对象的实例。
使用虚继承后就可以解决这个问题,即TopDiamond对象中只有一个Base对象的实例。
struct D1: virtual Base {};
struct D2: virtual Base {};
这是如何做到的呢,是在TopDiamond的构造函数中实现的。
详细的解释可以参考《深入探索C++对象模型》,里面会有对象内存布局,构造顺序等的解释。
回到本文的主题:
(1) finaClass继承自Helper类,它是Helper的友元类,所以它能访问Helper中的私有成员。
(2)如果finaClass不是虚继承自Helper类,那么finaClass可以被继承。
因为Helper部分的构造是通过finaClass的构造函数来完成的,不归Derivation管。Derivation构造函数只用调用finalClass的构造函数就行,其它的不用它管。
(3)如果finaClass虚继承自Helper类,那么finaClass不能被继承。
因为Helper部分的构造是通过Derivation的构造函数来完成的,而Derivation类不能访问Helper的私有成员,所以编译报错。