effective C++讲解了很多我们对继承认识的误区,书的最后特别对为什么C++要这样做做了详细的解释,了解了为什么要这样之后,我们会对继承机制有更深的了解,推荐大家去读一下。
pdf下载地址:点击下载:http://download.csdn.net/detail/hanbingfengying/7478915
条款36:区分接口继承和实现继承
继承的概念看起来很简单,进一步分析,会发现它由两个可分的部分组成:函数接口的继承和函数实现的继承。
这一条重点要我们理解纯虚函数、简单虚函数和非虚函数的区别,它们对应我们想要派生类继承的仅仅是接口还是接口还是一个缺省实现?
定义纯虚函数的目的在于,使派生类仅仅继承抽象类的接口。
一些函数不能在派生类中重定义,这样我们就必须把它定义为非虚函数。
条款37:绝不要重新定义继承而来的非虚函数
请阅读下面代码,查看代码运行结果:
#include "stdafx.h"
#include <iostream>
using namespace std;
class A{
public:
void func(){
cout << "A" << endl;
}
};
class B: public A{
public:
void func(){
cout << "B" << endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
B b;
A *a = &b;
a->func();
b.func();
b.A::func();
return 0;
}
答案是: A B A
相信聪明的你在看了
b.A::func();
这句代码后立马就能猜想到其中的原因。
虚函数是动态绑定的,而非虚函数在继承的时候是静态绑定的。所以如果子类重定义了非虚函数,就会出现这种伪二义的问题。
条款38:绝不要重新定义继承而来的缺省参数值
这一条需要格外注意,即使对于有经验的人来说,这里也极易出错。
阅读下面代码,查看运行结果:
#include "stdafx.h"
#include <iostream>
using namespace std;
enum ShapeColor { RED, GREEN };
class A{
public:
virtual void func(ShapeColor color = RED){
cout << "red" << color << endl;
}
};
class B: public A{
public:
void func(ShapeColor color = GREEN){
cout << "green" << color << endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
cout << "red:0 green:1"<< endl;
B b;
A *a = &b;
a->func();
b.func();
b.A::func();
return 0;
}
运行结果为
发现派生类对象的func调用了两次,但是两次默认的形参值不一样。
当派生类通过基类对象指针调用继承的虚函数时,传的默认形参是基类的默认形参。
这是为什么呢?
虚函数是动态绑定而缺省参数值是静态绑定的。这意味着你最终可能调用的是一个定义在派生类,但使用了基类中的缺省参数值的虚函数:
a->func();
这只是c++继承的基础理解,如果你没有读过《effective C++》,相信它一定不会让你失望的。
点击下载:http://download.csdn.net/detail/hanbingfengying/7478915