(一)
慎用多重继承,因为那样的话可能会造成歧义。。
<pre name="code" class="cpp">class BorrowableItem {
public:
void checkOut();
};
class ElectronicGadet {
private:
bool checkOut() const;
};
class MP3Player : public BorrowableItem
<pre name="code" class="cpp" style="font-size: 16px; line-height: 28px;"> public ElectronicGadet{...}; MP3Player mp; mp.checkOut();//歧义,调用的是哪个checkOut?
这与C++用来解析重载函数调用的规则相符:在看到是否有个函数可取用之前,C++首先确认这个函数对此调用之言是最佳匹配。找到最佳匹配函数后才检验其可取用性。本例中连最佳匹配都出现歧义,所以是否可取用就免谈了。mp.BorrowableItem::checkOut();
你当然也可以明确调用mp.ElectronicGadget::checkOut(),但然后你会获得一个“尝试调用private成员函数”的错误。
(二)
如果base
classes在继承体系中又有更高级的base classes,非virtual继承会造成多份base
class成员变量。这时要用virtual继承。为了这样做,你必须令所有直接继承自它的classes采用“virtual继承”
下面这种缺省行为会导致类IOFile的对象中有两份File的副本:
class File{...};
class InputFile: public File {...};
class OutputFile: public File{...};
class IOFile: public InputFile,
public OutputFile
{...}; 下面这种虚继承的行为会导致类IOFile的对象中只有一份File的副本:
class File{...};
class InputFile: virtual public File {...};
class OutputFile: virtual public File{...};
class IOFile: public InputFile
public OutputFile
{...};
(1)使用virtual继承的那些classes所产生的对象往往比使用non-virtual继承的兄弟们体积大,访问virtual base classes的成员变量时,也比访问non-virtual base classes成员变量速度慢。
(2)class若派生自virtual base class而需要初始化,必须认知其virtual bases----不论那些bases距离多远。
(3)当一个新的derived
class加入继承体系中,它必须承担起virtual bases(不论直接或间接)的初始化工作。
(4)我们对virtual继承的忠告:第一,非必要不要使用virtual bases;
第二,如果必须使用virtual bases,尽可能避免在其中放置数据。
多重继承的确有正当用途。其中一个情节涉及“public继承某个interface
class”(接口)和“private继承某个协助实现的class”(实现)的两相结合。例子:
class Iperson {
public:
virtual ~IPerson();
virtual std::string name() const=0;
virtual std::string birthDate() const=0;
};
class DatabaseID { ... }; //稍后被使用
class PersonInfo { //这个class有若干有用函数,可用以实现IPerson接口
explicit PersonInfo(DatabaseID pid);
virtual ~PersonInfo();
virtual const char* theName() const;
virtual const char* theBirthDate() const;
virtual const char* valueDelimOpen() const;
virtual const char* valueDelimClose() const;
};
const char* PersonInfo::valueDelimOpen() const {
return "["; //缺省的起始符号
}
const char* PersonInfo::valueDelimClose() const {
return "]"; //缺省的结尾符号
}
const char* PersonInfo::theName() const {
static char value[Max_Formatted_Field_Value_Length]; //保留缓冲区给返回值使用:static,自动初始化为“全0”
std::strcpy(value, valueDelimOpen()); //写入起始符号
... //将value内的字符串附到这个对象的name成员变量中
std::strcat(value, valueDelimClose()); //写入结尾符号
return value;
}
class CPerson : public Iperson, private PersonInfo { //注意,多重继承
public:
explicit Cperson(DatabaseID pid) : PersonInfo(pid) {}
virtual std::string name() const { //实现必要的IPerson成员函数
return PersonInfo::theName();
}
virtual std::string birthDate() const { //实现必要的IPerson成员函数
return PersonInfo::theBirthDate();
}
private:
const char* valueDelimOpen() const { //重新定义继承而来的virtual“界限函数”
return "";
}
const char* valueDelimClose() const {
return "";
}
};
(1)所以theName返回的结果不仅仅取决于PersonInfo也取决于从PersonInfo派生下去的classes。
(2)Cperson和personInfo的关系是,PersonInfo刚好有若干函数可帮助Cperson比较容易实现出来。因此它们的关系是is-implemented-in-term-of(根据某物实现出)。这种关系可以两种技术实现:复合和private继承。一般复合比较受欢迎,但是在本例之中Cperson要重新定义valueDelimOpen()和valueDelimClose(),所以直接的解法是private继承。
(3) 多重继承&单一继承比较,它通常比较复杂,使用上也比较难以理解,所以如果你有个单继承的设计方案,而它大约等价于一个多重继承设计方案,那么单一继承设计方案几乎一定比较受欢迎。
(4) 如果你唯一能够提出的设计方案涉及多重继承,你应该更努力想一想:几乎可以说一定会有某些方案让单一继承行得同。
(5) 然而多继承有时候的确是完成任务之最简洁、最易维护、最合理得做法,果真如此就别害怕使用它。
(1)多重继承比单一继承复杂。它可能导致新的歧义性,以及对virtual继承的需要。
(2)virtual继承会增加大小、速度、初始化(及赋值)复杂度等等成本。如果virtual base classes不带任何数据,将是最具实用价值的情况。
(3)多重继承的确有正当用途。其中一个情节涉及“public继承某个Interface class”和“private继承某个协助实现的class”的两相组合。
Effective C++:条款40:明智而审慎地使用多重继承,布布扣,bubuko.com
Effective C++:条款40:明智而审慎地使用多重继承
原文地址:http://blog.csdn.net/u010470972/article/details/37504367