条款39:明智而审慎地使用private继承

考虑如下代码:

class Person {};
class Student : private Person {};
void eat(const Person& p);		// 任何人都会吃
void study(const Student& s);	// 只有学生在校学习

Person p;	// p是人
Student s;	// s是学生

eat(p);		// 没问题
eat(s);		// 错误!难道学生不是人?

上述eat(s)错误的原因有两点:

  1. 如果classes之间的继承关系是private,编译器不会自动将一个derived class对象转换成一个base class对象
  2. private class继承而来的所有成员,在derived class中都会变成private属性,即使它们在base class中原本是protectedpublic属性

Private继承意味着is-implemented-in-terms-of(根据某物实现出),但是条款38指出复合(composition)的意义也是这样,如何取舍?答案是:尽可能使用复合,必要时才使用private 继承

假设我们有一个类Widgets想知道Wdiget成员函数多么频繁地被调用,也想知道经过一段时间后调用比例如何变化;

以宁可复用代码,也少些新代码的原则:考虑如下:

class Timer {
public:
	explicit Timer(int tickFrequency);
	virtual void onTrick() const; //定时器每滴答一次,此函数就被自动调用一次
};

为了让Widget重新定义Timer内的virtual函数,Widget必须继承自Timer;但public继承在此比例并不适当,因为Widget并不是个Timer;我们以private形式继承Timer:

class Widget : private Timer {
private:
	virtual void onTick() const; //查看Widget的数据...等等
};

这是一个好设计,但不值几个钱,因为private继承绝非必要,如果我们决定以复合取而代之,是可以的:

class Widget{
private:
	class WidgetTimer : public Timer {
		public:
			virtual void onTick() const;
			// ...
	};
	WidgetTimer timer;
};

//待补充…


技术上的原因,C++裁定凡是独立对象都必须有非零大小,如下代码:

class Empt{};	 // 没有数据,所以对象应该不适用任何内存

class HoldsAnInt {	//应该只需要一个int空间
private:
	int x;
	Empty e;		//应该不需要任何内存
};

然而上述代码你会发现sizeof(HoldAnInt)>sizeof(int),再大多数编译器中sizeof(Empty)获得1,因为面对"大小为零之独立对象",通常C++官方勒令默默安插一个char到空对象内;但是这个约束不适用于derived class对象内的base class成分,因为它们并非独立(非附属);如果你继承Empty,而不是内含一个那种类型的对象:

class HoldsAnInt : private Empty {
private:
	int x;
};

几乎可以确定上述代码szieof(HoldsAnInt) == sizeof(int),这就是所谓的EBO(空白基类最优化)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值