14-04-29 补充 http://blog.csdn.net/haoel/article/details/1948051 C++ 虚函数表解析
虚函数是动态绑定的基础,虚函数必须是非静态的成员函数,虚函数经过派生之后,在类族中就可以实现运行过程中的多态.
根据类型兼并原则,可以用派生类对象来代替基类的对象,但是用基类的指针指向派生类的对象的时候,如果派生类对象存在和基类同名的成员函数,如果想要运行的是派生类的成员函数,需要将基类的该成员函数声明为虚函数,来实现运行时多态。
运行时多态需要满足三个条件:1)符合类型兼并原则2)要声明虚函数3)由成员函数来调用或者通过指针、引用来访问虚函数。
如果是通过使用对象名来访问虚函数,则绑定在编译过程中就可以进行(静态绑定),而无需在运行过程中进行。
#include <iostream>
using namespace std;
#include <cstdio>
#include <cstdlib>
class B0{
public:
virtual void display(){
cout << "B0::display()" << endl;
}
};
class B1:public B0{
public:
void display(){
cout << "B1::dispaly()" << endl;
}
};
class D1:public B1{
public:
void display(){
cout << "D1::dispaly()" << endl;
}
};
void fun(B0 *p){
p->display();
}
int main(){
B0 b0,*p;
B1 b1;
D1 d1;
p = &b0;
fun(p);
p = &b1;
fun(p);
p = &d1;
fun(p);
system("pause");
}
运行结果如下:
本程序中,派生类并没有显示给出虚函数声明,这时系统就会遵循以下规则来判断派生类的一个函数成员是不是虚函数:
1)该函数是否和基类的虚函数有相同的函数名;
2)该函数是否与基类的虚函数有相同的参数个数以及相同的对应参数类型;
3)该函数是否与基类的虚函数有相同的返回值或者满足类型兼容原则的指针、引用型的返回值
如果从名称、参数、返回值三个方面检查之后,派生类的函数满足了这一条件之后,就会自动确认为虚函数,这时,派生类的虚函数就覆盖了基类的虚函数,不仅如此,派生类中的虚函数还会隐藏基类中同名函数的所有其他重载形式。
当基类构造函数调用虚函数时,不会调用派生类的虚函数.假设有基类Base和派生类Derived,两个类中有虚成员函数virt(),如果Bse::Base()调用了虚函数virt(),则被调用的是Base::virt(),而不是Derived::virt().因为当基类被构造时,对象还不是一个派生类的对象.
同样 当基类被析构时,对象已经不再是一个派生类对象了,所以如果Base::~Base()调用了virt(),则被调用的是Base::virt(),而不是Derived::virt()
虚析构函数
如果一个类的析构函数是虚函数,那么,由它派生的所有子类的析构函数也是虚函数,
简单来说,如果有可能通过基类指针调用派生类的析构函数,那么需要将基类的析构函数声明为虚函数
#include <iostream>
using namespace std;
#include <cstdio>
#include <cstdlib>
class Base{
public:
virtual ~Base(){
cout << "base destructor" << endl;
}
};
class Derived:public Base{
public:
Derived();
~Derived();
private:
int *i_pointer;
};
Derived::Derived(){
i_pointer = new int(0);
}
Derived::~Derived(){
cout << "Derived destructor" << endl;
delete i_pointer;
}
void fun(Base *b){
delete b;
}
int main(){
Base *b = new Derived();
fun(b);
system("pause");
}
这是例子是通过虚析构函数实现了多态
纯虚函数
纯虚函数是一个在基类中声明的虚函数,它在该基类中没有定义具体的操作内容,要求各派生类具体实现自己的版本.
1)声明为纯虚函数后,基类中就不能给出函数的实现部分
2)带有纯虚函数的类是抽象类
3)抽象类不能实例化,但是可以声明一个抽象类的指针和引用,通过指针和引用,我们就可以指向并访问派生类对象,故而访问派生类的成员,这种访问是多态特性的
#include <iostream>
using namespace std;
#include <cstdio>
#include <cstdlib>
class B0{
public:
virtual void display() = 0;
};
class B1 : public B0{
public:
void display(){
cout << "B1::display()" << endl;
}
};
class D1: public B1{
public:
void display(){
cout << "D1 :: dispaly()" << endl;
}
};
void fun(B0 *ptr){
ptr->display();
}
int main(){
B0 *p;
B1 b1;
D1 d1;
p = &b1;
fun(p);
p = &d1;
fun(p);
system("pause");
}
B0、B1、D1属于同一个类族,B0提供了类的一个接口,B1、D1类提供了类的具体实现,抽象类B0类型的指针指向派生类的对象,b1和d1
同时 派生类的虚函数没有用virtual声明,但是他们由系统判定为虚函数
带有纯虚函数的类是抽象类,抽象类不能实例化,即不能创建对象,只要有纯虚函数没有实现的类都是抽象类,如果所有的纯虚函数都实现了,那么这个派生类不在是抽象类.