虚函数
- 通过基类的指针删除派生类对象时,通常只调用基类的析构函数
- 但是删除一个攀升类对象时,应该先调用派生类的析构函数,然后调用基类的
- 解决办法:把基类的析构函数声明为virtual
- 派生类的析构函数可以virtual不进行声明
- 通过基类指针删除派生类对象时,首先调用派生类的析构函数,然后调用基类的析构函数
- 一般来说,一个类如果定义了虚函数,则应该将析构函数也定义成虚函数。或者,一个类打算作为基类使用,也应该将析构函数定义成虚函数
NOTICE:不允许将构造函数声明为虚函数
class son {
public:
~son() {cout << "bye feo son" << endl;}
};
class grandson:public:son {
public:
~grandson() {cout << "bye from grandson" << endl;}
};
main() {
son * pson;
pson = new grandson();
delete pson;
} // 输出 bye from son 没有执行 grandson::~grandson()!!!
纯虚函数和抽象类
纯虚函数:没有函数体的虚函数
class A {
private: int a;
public:
virtual void Print() = 0; // 纯虚函数
void fun() { cout << "fun"; }
};
包含纯虚函数的类叫做抽象类
- 抽象类只能作为基类来派生新类使用,不能创建抽象类的对象
- 抽象类的指针和引用可以指向抽象类派生出的类的对象
A a; // wrong A是抽象类,不能创建对象
A * pa; // ok 可以定义指针和引用
pa = new A; // wrong 不能创建对象
- 抽象类的成员函数内可以调用纯虚函数,但是在构造函数或析构函数内部不能调用纯虚函数
- 如果一个类从抽象类派生而来,那么当且仅当它实现了基类所有纯虚函数,它才能成为非抽象类
class A {
public:
virtual void f() = 0; // 纯虚函数
void g() { this->f(); } // ok 多态,一定是派生类的f()
A() { f(); // 错 不是多态,函数体都没有 }
};
class B:public A {
public:
void f() { cout << "B:f()" << endl; }
};
main() {
B b;
b.g(); // 输出B:f()
}