virtual inheritance 的妙用--------实现final类
cppbug cpp_bug@hotmail.com
一提起virtual inheritance,我们便会立刻把它与multiple inheritance 联系起来,因为multiple inheritance会产生一种DDD(dreadful diamond of derivation)的问题。通过virtual inheritance可以解决。关于这点不必多说,下面我们来看virtual inheritance的另外一个应用。
首先我们知道,virtual inheritance所带来的一个效果就是由派生层次最深的类来完成根类子对象的创建,即由派生层次最深的类来调用根类子对象的构造函数,比方说:
class Base{};
class Derived1:virtual public Base{};
class Derived2:virtual public Base{};
class Mderived:public Derived1,public Derived2{};
对于上面这段代码,当用Mderived类构造对象的时候,因为这里采用了virtual inheritance,并且Mderived类是派生层次最深的类,所以将会由Mderived来完成根类Base子对象的构建,而不是由类Derived1和Derived2来完成。
但是请你注意,并不一定每个派生层次最深的类都具有创建根类子对象的权限,所以final类的实现恰恰是巧妙的利用了这一点,我们先来看下面这段代码:
namespace Private
{
class NoderivedHelper
{
NoderivedHelper(){}
friend class Noderived;
};
}
class Noderived:private virtual Private::NoderivedHelper //此处也可以是public继承,没
{ //有影响
…
};
在上面这段代码中,Noderived类由于是NoderivedHelper类的友元类,因此它可以完成基类子对象的创建,也就是说它有权限调用NoderivedHelper类的构造函数。但是如果我们想要从Noderived类进行派生,就会发生错误。为什么呢?就是由于这里采用了virtual inheritance,根类子对象必须由派生层次最深的类来创建的原因。比如:
class D:public Noderived{}
这里根类子对象必须由D类来创建,但是由于D类不是NoderivedHelper的友元类,因此它没有权限调用NoderivedHelper类的构造函数,无法对根类子对象进行构建。我想大家对实现final类的基本原理应该已经理解,但是上面的代码由于有friend class Noderived;这一行,采用了硬编码的方式,因此它的适用性很差,我们进行以下改进,去掉friend这一行:
namespace Private
{
class NoderivedHelper
{
protected: //这里由private变为protected
NoderivedHelper(){}
};
}
class Noderived:private virtual Private::NoderivedHelper //这里必须是private继承
{
…
};
ok,现在NoderivedHelper类的适用性明显增强,而且也可以达到相同的效果,这又是为什么呢?关键是这里采用了私有继承,从而NoderivedHelper类将作为Noderived类的私有内部组件,也就是说NoderivedHelper类的默认构造函数对于从Noderived类派生的类来说变为私有不可访问。因此当派生层次最深的类创建根类子对象的时候就会出现没有权限调用根类构造函数的情况,从而发生错误。但是现在这个版本还有缺陷,看下面这种情况:
class D: private virtual Private::NoderivedHelper ,public Noderived{}
现在类D就可以从Noderived类中进行派生。因为virtual inheritance使得只有一个根类子对象的副本,并且类D可以从第一个继承中获得创建根类子对象的权限,因此就可以完成对象的构造
下面我们再来改进这个缺陷:
namespace Private
{
class NoderivedHelper
{
protected:
NoderivedHelper(int){}
};
}
class Noderived:private virtual Private::NoderivedHelper
{
public:
Noderived():NoderivedHelper(0){}
};
现在缺陷没有了,通过那个dummy value,使得即使在class D: private virtual Private::NoderivedHelper ,public Noderived{}的情况下,类D也无法被正常的构造,因为类D在创建根类子对象的时候并不会为NoderivedHelper类的构造函数提供参数,所以无法完成对象的构造。
现在我想大家已经清楚了virtual inheritance所带来的又一应用了吧:)
(全文完)
reference:
<<c++ view>> 第一期