一、函数的隐藏与覆盖
曾经看孙鑫的《VC++深入详解》,在C++基础中提到过函数的隐藏与覆盖,不懂的同学可以去搜,当时没能理解其精髓,后来看到ACE代码,很多析构函数都是虚函数后,开始去搜了。
继承是动态多态的支撑点,继承的时候,public的成员和方法都是直接可以使用的,当子类函数与父类函数同名时,父类方法就被隐藏了;而如果父类方法是虚函数,则父类方法被覆盖(Java貌似是直接写override,重写)。当然,要覆盖,必须函数列表相同,位于父类和子类中,必须声明virtual。
以如下测试代码为例
//============================================================================
// Name : Iherit.cpp
// Author : xia
// Copyright : NUAA
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <iostream>
using namespace std;
class Person {
public :
Person() {
cout << "Person constructor" << endl;
}
virtual ~Person() {
cout << "Person destructor" << endl;
}
virtual void say() {
cout << "Person says " << endl;
}
};
class boy:public Person {
public:
boy() {
cout << "boy constructor" << endl;
}
virtual ~boy() {
cout << "boy destructor" << endl;
}
void say() {
cout << "boy says " << endl;
}
};
int main() {
Person *xiaoli = new boy;
xiaoli->say();
delete xiaoli;
return 0;
}
当去掉Person类中say()方法 前的virtual后,输出结果为
Person constructor
boy constructor
Person says
boy destructor
Person destructor
由于没有virtual关键字,没有通过v-table找到子类的say方法,所以虽然是子类对象,由于是父类指针,依旧调用了父类方法(如果想多态,这肯定不是我们的目的;毕竟多态的一个大应用就是向上转换,统一用父类指针调用子类方法),加上virtual后,则输出boy says
二、virtual与构造函数、析构函数
《C++编程思想》上有说过,构造函数不能为虚函数,为什么呢?一个原因是虚函数能调用在派生类的函数,如果我们在构造函数中这样,我们调用的函数可能操作还没有初始化的成员(因为子类对象要先调用父类的构造函数),这会导致灾难发生。另一个原因是,当一个构造函数被调用时,它要做的首要事情之一是初始化它的VPTR。
不过很多时候析构函数却必须为虚函数,为什么呢?同样是由于当父类指针指向子类对象时,如果父类析构不是虚函数,则执行时,不能执行到子类的析构函数。以上面示范代码为例,如果去掉Person中析构函数的virtual关键字,则输出
Person constructor
boy constructor
Person says
Person destructor
并没有调用到boy的析构函数,加上后,可以看到是调用了的。
以前测试代码,并没有使用父类指针去指向子类对象,忘了充分使用多态,所以并没有体会到隐藏和覆盖 以及虚函数的一些更 high的地方,正好碰到了,就总结下吧。