《Effective C++》第六章:继承与面向对象设计

26 篇文章 1 订阅

条款32:确定你的public继承塑模出is-a关系

is-a的关系就是说派生类一定是一个基类,额,通俗一点说就是派生类可以当做基类一样来使用。即本章阐述的观点就是,public继承就意味着is-a。适用于base classes身上的每一件事一定也适用于derived classes身上,确保base能做的事,derived也一定可以做

条款33:避免遮掩继承而来的名称

考虑下面这个例子:

class Base
{
private:
	int x;
public:
	virtual void mf1() = 0;
	virtual void mf1(int);
	virtual void mf2();
	void mf3();
	void mf3(double);
};

class Derived:public Base
{
public:
	virtual void mf1();
	void mf3();
	void mf4()
};
Derived d;
int x;
d.mf1();
d.mf1(x);    //报错
d.mf2();
d.mf3();
d.mf3(x);    //报错
由此可见,派生类会遮掩基类的名称,无论重载。我们可以使用using来使得名字可见。

条款34:区分接口继承和实现继承

身为class设计者,有时候你会希望只继承成员函数的接口(纯虚函数);有时候你又会希望derived class同时继承函数的接口和实现,但又希望能够覆写实现(虚函数);又有时候你希望derived class同时继承函数的接口和实现,但不允许覆写任何东西(普通函数)。

条款35:考虑virtual函数以外的其他选择

1、借由Non-Virtual Interface手法实现Template Mehod模式

即将virtual函数声明为private,由public非虚函数调用这个虚函数..就是在virtual实现了一层封装,可以在虚函数调用前后做一些操作

2、由函数指针实现回调

3、所谓的Strategy模式,个人理解为复合,将基类A当做一个类B的成员变量,这样的话,每个A的派生类都适用于B(而且A的派生类可能重写A中的虚函数),比如下面例子:

class GameCharacter;
class HealthCalcFucn
{
public:
	virtual int calc(const GameCharacter& gc) const;
};

class GameCharacter
{
public:
	explicit GameCharacter(HealthCalcFucn *phcf);
	int healthValue()
	{
		pHealthCalc(*this);
	}
private:
	HealthCalcFucn *pHealthCalc;
}
这样每个HealthCalcFunc的派生类都适用于GameCharacter这个类。

条款36:绝不重新定义继承而来的non-virtual函数

假设我们定义以下关系:

class B
{
public:
	void mf();
};
class D:public B{ ... };

//对于以下调用
D x;
B* pb = &x;
pb->mf();

D* pd = &x;
pd->mf();
两者调用的是同一个mf()函数么?其实有可能不是一个。虽然pb和pd都指向了同一个对象。如果D也定义了自己的一份mf()那么就会发生上述情况。因为对于non-virtual的调用都是静态绑定。而虚函数却是动态绑定的。一旦重新定义了继承而来的非虚函数,那么每一个D都是一个B就不为真,违反了is-a的设计原则,并且如果D真的有必要实现与B不同的mf(),那么应该将mf()声明为virtual。

条款37:绝不重新定义继承而来的缺省参数值

由于上一条款绝不重新定义继承而来的non-virtual函数,所以本章讨论将局限于继承一个带有缺省参数值的virtual函数。那么本条款成立的理由十分明确:virtual是动态绑定,而缺省参数却是静态绑定。所以即使派生类重新定义了缺省参数值,参数值也不会表现为多态。解决方法是条款35提出的NVI(non-virtual-interface)手法,将缺省参数放在public非虚函数上,而将虚函数声明为private。

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

当复合发生于应用域的对象之间,表现出has-a的关系;当它发生于实现域内则是表现出根据某物实现出的关系。......抽象

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

探讨的是private继承,public继承是is-a关系,而private继承纯粹是一种实现技术,意味着只有实现被继承,而接口被略去,即上一条款所说的根据某物实现出的概念。那么什么时候用复合,什么时候用private继承呢?首先我们从类的大小来分析。一个空类或者不含数据成员的类大小通常为1个字节,当使用复合的时候,这个类成员会占用4个字节,因为边界对齐。如果使用private继承,这个类是不占用空间的。另外如果想使用一个类的protected成员,那么必须是private继承了。



over...这一章节算是更完了



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值