Effective C++ 条款38、39

条款38 通过复合塑模出has-a或“根据某物实现出”

复合(composition)是类型之间的一关系,当某种类型的对象内含其它种类型的对象时,就是复合关系。

复合在实现域意味has-a(有一个)。在实现域,复合意味is-implemented-in-terms-of(根据某物实现出)

class Address{};
class PhoneNumber{};
class Person {
public:
	...
private:
	string name;       //合成成分物
	Address address;   //合成成分物
	PhoneNumber voiceNumber;  //合成成分物
	PhoneNumber faxNumber;//合成成分物
};

区分is-a(是一种)和is-implemented-in-terms-of(根据某物实现出)两种对象关系。

考虑一个template,制造出一组class用来表现由不重复对角组成的set。通地复用方法,让set template继承list,于是代码如下,

template<typename T>   //将list应用于Set。是错误的做法
class Set:public list<T>{...};

上述做法错误的原因,public继承是is-a的关系,也就是Set的对象一定是List<T>对象,但我们知道,B有时表现出的的物性,不是D所需的,即D不是一种B。

于是转变策略,Set对象可根据一个list对象实现(is-implemented-in-terms-of)出来:

template<class T>
class Set {
public:
	bool member(const T& item)const;
	void insert(const T& item)const;
	void remove(const T& item)const;
	size_t size()const;
private:
	list<T> rep;//用来表述Set的数据(复合的实现域用法)
};

template<class T>
bool Set<T>::member(const T& item)const {
	return find(rep.begin(), rep.end()) != rep.end();
}

template<class T>
void Set<T>::insert(const T& item)const {
	if (!member(item))
		rep.push_back(item);
}

template<class T>
void Set<T>::remove(const T& iterm)const {
	typename list<T>::iterator it = find(rep.begin(), rep.end(), item);//此处利用typename表明list<T>::iterator是一个嵌套从属名称
	if (it != rep.end()) rep.erase(it);
}

template<class T>
size_t Set<T>::size() const {
	return rep.size();
}

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

统御private继承的首要规则:

i、如果class之间的继承关系是private,编译器不会自动将一个derived class对象转换为一个base class对象。

ii、由private base class继承而来的所有成员,在derived class都会变成private属性,纵使它们在base class中原本是protected或public属性。

需要注意:private继承意味只有实现部分被继承,接口部分应略去。private继承意味is-implemented-in-terms-of(根据某物实现出)。尽可能使用复合,必要时才使用private继承

以下利用private继承及其改进版的代码举例,

class Timer {
public:
	explicit Timer(int tickFrequency);
	virtual void onTick()const;//定时器每滴答一次,此函数就被自动调用一次
};
以private形式继承Timer,
class Widget :private Timer {
private:
	virtual void onTick()const;//查看Widget的数据...等等
};
对private继承形式,利用继承+复合版本进行改进,
//继承+复合代替private继承
class Widget {
private:
	class WidgetTimer :public Timer {
	public:
		virtual void onTick()const;
		...
	};
	WidgetTimer timer;//定义一个对象的前提,必须给定类的WidgetTimer的定义式,
};                    //因为编译器在给其生成一个对象时,必须知道该类的大小。
另外一知识点, C++裁定凡是独立(非附属)对象都必须有非零大小。由于前提是非附属哈,所以此约束不适用于derived class对象内的base class成分,以下均用代码验证,
class Empty {};//没有数据,所以其对象应该不使用任何内存

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

在32位的机器上,对上述使用sizeof(HoldsAnint)=8。

现实中的“empty”classes并不真的是empty。

class HoldsAnInt :private Empty {
private:
	int x;
};
在32位的机器上,对上述使用sizeof(HoldsAnint)=sizeof(int)=4,即所谓的空白基类最优化(EBO)。
此部分具体细节分析见本人另一篇博客。

以上内容均来自Scott Meyers大师所著Effective C++ version3,如有错误地方,欢迎指正!相互学习,促进!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值