《Effective C++》读书笔记 条款39:明智而审慎地使用private继承

我们已经知道public继承是is-a的关系,在public继承的情况下一个派生类可以暗自转换成一个基类,也就是在需要基类参数的地方传递派生类也是可以的,毕竟public继承是is-a的关系。但是对于private继承情况就不一样了,先看下面这段代码。

class Student :private Person
{
};
void eat(const Person& p)
{

}
void study(const Student &s)
{

}
int main()
{
	Student s;
	Person p;
	//eat(s); //出错error C2243: “类型转换”: 从“Student *”到“const Person &”的转换存在,但无法访问
	study(s);
	return 0;
}

 

对于上面的student类,它private继承自Person,但是我们给一个需要基类Person的函数eat传递派生了student发现是行不通的,编译器报错,上面那个错误是我在用VS2013运行时报的错,这也就是说private继承与public继承是不同的,private继承不是is-a关系。 

private继承其实意味着implemented-in-terms-of(根据某物实现出)。private继承意味着你要用基类已经具备的某些特性去实现派生类的一些功能。这个特点让我们想到了复合,复合也有这一功能,那么我们应该用哪一种呢?答案是尽量用复合,只在牵扯到protected成员和virtual函数时才用private。

如果我们设计一个类,要用到另一个类的某些特性,但我们设计的这个类又不能说是那个类,比如我们之前说过的用list实现set,我们不能说set是一个list,所以不能用public继承,在上一次的讲解中用的是复合,但是如果涉及到要使用虚函数和访问protected成员的操作,复合就不能实现了,而这一讲告诉我们可以用private继承。但是这不涉及protected成员和virtual函数时,还是尽量用复合。那么除此之外private继承还有一个好处,我们来看下面这段代码:

#include <iostream>

class Person{
};
class Student :private Person
{
private:
	int ID;
};
class Worker
{
private:
	int ID;
	Person p;
};
int main()
{
	Person p;
	Student s;
	Worker w;
	std::cout << sizeof(p) << std::endl;  //1
	std::cout << sizeof(s) << std::endl;  //4
	std::cout << sizeof(w) << std::endl;  //8
	return 0;
}

 

首先,一个空类的大小不是0,是1,这主要是因为面对“大小为0的独立(非附属)对象”,通常C++官方勒令默默安插一个char到空对象内。所以sizeof(p)是1,而对于sizeof(w)由于存在内存对齐,编译器为其补充了3个空格,所以是8,但是如果是继承,因为不是独立对象了,C++就不进行默默安插char的操作了,所以对于sizeof(s),由于Person是空类,所以为4。这是所谓的EBO(empty base optimization:空白基类最优化)。EBO只在单一继承(而非多重继承)下才可行。

因为复合比较容易理解,所以无论什么时候,只要可以,选择复合而不是private继承。

请记住:

1.Private继承意味着is-implemented-in-terms-of(根据某物实现出),它通常比复合的级别低(意思就是优先考虑复合)。但是当派生类需要访问protected base class的成员,或需要重新定义继承而来的virtual函数时,这么设计是合理的。

2.和复合不同,private继承可以是empty base最优化。这对致力于“对象尺寸最小化”的程序库开发者而言,可能重要。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值