关于多重继承中覆盖虚基类的函数问题--《C++程序设计语言》

来源:互联网 发布:qt wifi windows 编辑:程序博客网 时间:2024/06/05 03:31

裘宗燕翻译的《c++程序设计语言(特别版)》第356页和357页分别有以下两段描述,

1.如果不同的派生类覆盖了同一个函数,那又会怎么样呢?当且仅当某个覆盖类是从覆盖此函数的每个类派生出时,才允许这样做。也就是说,必须有一个函数覆盖了所有其他的覆盖函数。


2.如果两个类覆盖了同一个基类函数,但它们互不覆盖,这个类层次结构就是错的。

这两段话其实说的是同一个意思。 用代码表示如下:


class Base
{
public:
virtual void read() = 0;
virtual void write() = 0;
};

class SubA : public Base
{
public:
void read() { cout << "SubA read()" << endl;}

};

class SubB : public Base
{
public:
void read() { cout << "SubB read()" << endl;}
};

class SubC : public SubA, SubB
{
public:
void write() { cout << "SubC write()" << endl;}
void read() { SubA::read();}
};


就是说:如果SubA和SubB两个Base的派生类,都覆盖(override)了Base类中的函数read(),那么情况会如何呢?

这个时候,正确的类结构关系,就是如2楼所说的,菱形继承,即: 在实际运用中,SubA和SubB有一个共同的父类Base,也应该共同派生一个子类SubC,同时在这个SubC中,也应该同样地覆盖那个被SubA和SubB均覆盖的函数,read()。这样作当然是为了在SubC中避免歧义(ambiguous)。

从语法上而言,如果你的SubC不定义一个覆盖函数read(),也是可以的(只要你的程序中不通过SubC调用read即可),一样能编译通过,并正常运行。 但正如5楼说的那样,这种方式很容易在实际项目中引起混乱。因此应该予以纠正,一种可能的方式就是,SubC中也定义一个空的覆盖函数,即时这个函数什么都不作也好。

由于手头没有pdg的书及阅读器,因此花了点时间找到了这本书的pdg中文版本,以及pdgreader(不错的绿色软件,推荐一下,~~)。看了一下,发觉裘教授翻译还算是不错的。lz给出的2段文字,分别对应于原书(The C++ Programming Language,3rd Edition)中的第401页中的倒数第9行和第402页中的第1行。原文引述如下:


What if different derived classes override the same function? This is allowed if and only if some overriding class is derived from every other class that overrides the function. That is, one function must override all others.



If two classes override a base class function, but neither overrides the other, the class hierarchy is an error. No virtual function table can be constructed because a call to that function on the complete object would have been ambiguous.


第2段话,裘教授翻译中的“它们互不覆盖”,并不很精确,因为类的互相覆盖本就是不可能存在的。原文的意思是说,(以上面的SubA和SubB为例)要么是SubA覆盖SubB,要么是SubB覆盖SubA,这两种情况都不存在的话,会如何如何,也即SubA和SubB不存在任意一种方向的派生关系。综述原文的意思,如果两个类覆盖了基类的函数(SubA和SubB覆盖了read()),而SubA和SubB又不是派生关系(即不是SubA的read覆盖了SubB的read,或者也不是SubB的read覆盖了SubA的read),那么(如果SubA和SubB没有一个共同的派生类SubC来覆盖它们中的父类覆盖函数read——理解SubA和SubB的时候使用了多态,认为是没有问题的,但是没有结合SubC去理解。这个时候如果在SubC里面不重写read()函数,就在SubC里面有两个继承而来的reac()函数,这个就带了二义性的问题。这个时候就使得类的结构出了问题。
)这个类的关系结构就存在问题了。。。。

也正因为如此,Java和C#中都取消了C++的多重继承(虽然还是可以通过Interface来实现多重继承)。多重继承本就是一把双刃利器。即便如此,在实际中超过3重的继承,还是应当尽量避免的。

然而,通过明确写出的方式消除歧义显得比较混乱,最好是通过在派生类里定义新函数的方式消除这类问题。

对应的原文是第391页:

However, explicit disambiguation is messy, so it is usually best to resolve such problems by defining a new function in the derived class:

说的其实就是解决之道。

转自:http://hi.baidu.com/savioryu/blog/item/1ebb86f53ad5d2e77609d7ff.html
原创粉丝点击