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

在类设计中,可以通过设置基类成员为纯虚函数、虚函数或非虚函数来控制派生类如何继承。纯虚函数使得派生类必须重写接口;虚函数允许派生类继承接口并能有自己的实现;非虚函数则要求派生类继承接口及实现,且通常不允许修改。这种策略影响了类的继承行为和多态性。
摘要由CSDN通过智能技术生成

作为类的设计者,我们有时候希望派生类只继承基类成员函数的接口,有时候希望派生类继承基类的接口及实现,同时又能自己重写这些实现,有时希望派生类老老实实的继承这些函数的接口和实现,而且不做任何修改。这三种不同的策略是通过声明基类成员为纯虚函数、虚函数和非虚函数来实现的。看一个例子:

class Animal
{
public:
	 virtual void eat() = 0;
	 virtual void move();
	 void mad();
};


class Bird:public Animal
{
public:
	void eat();
	void move();
};

void Animal::mad()
{
	cout<<"mad"<<endl;
}

void Animal::move()
{
	cout<<"move from A to B"<<endl;
}


void Bird::eat()
{
	cout<<"eat worm"<<endl;
}

void Bird::move()
{
	cout<<"fly from A to B"<<endl;
}

则对于eat函数你必须在派生类中给出声明和定义,否则派生类还是一个抽象类。对于move函数,假如你没有给出声明和定义,那么就会自动的去调用基类的move,而对于基类定义好的mad,你直接拿来用就好了,没有必要重新定义,因为重新定义会发生前一小节介绍的派生类函数屏蔽基类函数的问题。


当然,事情总有一些特例,比如,我们可以对基类的纯虚函数eat给出定义。

void Animal::eat()
{
	cout<<" eat everything"<<endl;
}

然后通过派生类去访问它:

	Bird b;
	b.Animal::eat();

不过这种用法并不常见。


对于虚函数,如果派生类定义了自己的版本,那么派生类的对象就会调用自己的;如果没有,就会调用基类。这本来是一件多么美好而方便的事啊!可是,它有可能让程序员忘掉了这个函数的行为不是这个类中定义的,而是一种默认的行为。我们希望的结果是告诉编译器我要用默认行为了,再用默认行为;如果我没说,请编译器提醒我这样做不对:

class Animal
{
public:
	 virtual void eat() = 0;
	 virtual void move() = 0;
	 void mad();
protected:
	void defaultMove();
};

void Animal::defaultMove()
{
	cout<<"move from A to B"<<endl;
}

void Bird::move()
{
	defaultMove();
//	cout<<"fly from A to B"<<endl;
}

首先,将move设为纯虚函数,并设定了defaultMove函数,那么在派生类的move中,如果我们要使用defaultMove,必须指明。有一点需要注意,此时defaultMove应该是一个非虚函数,这意味着派生类不应该重新定义它。因为如果它被重新定义,则整个默认动作就乱套了。


如果有人觉得这种办法会导致函数名引起的命名空间污染问题,还有一种办法可以解决,它利用了“我们可以给纯虚函数一个实现”:

void Animal::move()//纯虚函数的实现
{
	cout<<"move from A to B"<<endl;
}

void Bird::move()
{
	//调用纯虚函数的实现
	Animal::move();
//	cout<<"fly from A to B"<<endl;
}

此时,move仍为纯虚函数,但是我们给出了它的实现。如果我们想调用默认动作,必须显式指明使用的是基类中的move。


按照前面的论述,则可以避免两种常见的错误:
1.把基类中的所有函数都声明为非虚函数—这就意味着你不打算给派生类一点自我发挥的空间。而且如果析构函数不声明为虚函数,可能会带来各种问题。
2.将所有函数都声明为虚函数,但这也表明了你对自己的设计的基类很没有信心,基本没有什么东西是确定的。


总而言之,纯虚函数使得派生类只继承基类的接口;虚函数让派生类可以自我发挥,但是如果不想发挥,也可以提供默认版本;而非虚函数则要求你必须继承它,没有自由空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值