《Effective C++》读书笔记之item40:明智而审慎地使用多重继承

1.多重继承的缺点:

(1)从一个以上的基类继承相同名称,可能导致歧义,使用时应当使用域作用符限定具体是哪个基类的成员。注意:在这种歧义中,C++用来解析重载函数调用的规则在起作用——在看到是否有个函数可取用之前,首先确定这个函数对此调用来说是最佳匹配,找到最佳匹配函数后才检验其可取用性。

(2)如个一个基类有多个派生类,而更深层次的派生类从这些派生类中派生出来,基类如何构成这更深层次的派生类呢?

  • 从每一条路径中继承派生类,因而该派生类对象有两份甚至多份“基类”对象;
  • 但从基类中继承而来的这些对象不能重复。

C++缺省支持第一种方案,但是也可以支持第二种方案,此时应当使基类成为虚基类,因此应当使直接继承自基类的派生类都采用虚继承。STL中的输出输出流就采用类似的方法(采用类模板)。

2.实际使用中应尽量避免多重继承,而采用相同功能的单一继承方案。

3.尽量以虚继承的方式使用public继承。

但是虚继承有缺点:

  • (1)使用虚继承的派生类往往比非虚继承的类体积大,成员变量的访问速度也较慢。
  • (2)虚基类初始化问题:虚基类的初始化由继承体系中的最低层负责,这表示:
    • 1)派生自虚基类的类初始化时必须认知这个虚基类;
    • 2)当一个新的派生类加入到继承体系中,必须承担起虚基类(直接或间接)的初始化责任。

因此,对于虚基类,建议有:

  • (1)非必要不使用虚基类;
  • (2)如果必须使用,尽可能不在其中放置数据。(类似Java和.NET中的接口。)

4.实例:个人信息管理的例子:

假设有一个IPerson类表示“人”:

class IPerson{
	public:
		virtual ~IPerson();
		virtual std::string name() const = 0;
		virtual std::string birthDate() const = 0;
}


它使用工厂函数来返回派生类对象的(智能)指针:

std::tr1::shared_ptr<IPerson> makePerson(DatabaseID personIdentifier);


另外拥有一个PersonInfo类,它与数据库相关:

class PersonInfo{
	public:
		explicit PersonInfo(DatabaseID pid);
		virtual ~PersonInfo();
		virtual const char* theName() const;
		virtual const char* theBirthDate() const;
		...
	private:
		virtual const char* valueDelimOpen() const;	//“开始”符号,用于姓名的输出
		virtual const char* valueDelimClose() const;	//“结束”符号
		...
};


在这个PersonInfo::theName()函数中,将调用“开始”和“结束”符号的函数来输出经过修饰的名字:

const char* PersonInfo::theName() const{
	static char value[Max_Formatted_Field_Value_Length];	//保留缓冲区给返回值使用。注意由于缓冲区是static的,会被自动初始化为“全部是0”
	std::strcpy(value, valueDelimOpen());	//写入起始符号
	...	//添加姓名
	std::strcat(value, valueDelimClose());	//写入结束符号
	return value;
}


在这个类中,valueDelimOpen()和valueDelimClose()是虚函数,因而此函数的返回结果同时取决于PersonInfo和其派生类。对于IPerson的派生类,如CPerson类,作为“人”的具体实现者,应当改写name()和birthDate(),使其返回值中不带有开始和结束符号。

因此,CPerson应当使用PersonInfo中的功能(根据某物实现出),并且如果使用复合,由于PersonInfo类是虚基类,无法直接生成对象,则应当使用私有继承;同时对IPerson采用公有继承,以继承它的接口。结合起来应当是:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值