当前位置: 首页 > 工具软件 > ClassFinal > 使用案例 >

c++中不能被继承的类(c++ final class)

符修杰
2023-12-01

昨天有人问我这个问题,在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;
}

这里Helper是一个辅助类,用来帮助finalClass成为不能被继承的类。

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的私有成员,所以编译报错。


 类似资料: