C++中的虚函数的作用主要是实现了多态的机制,虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的,关于虚函数表的实现机制,可以参考这篇文章:C++ 虚函数经典深入解析。以下主要介绍下虚函数使用与非虚函数的区别。
1、非虚函数的调用
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
class base{
public:
void aprint(){
cout << "base aprint" << endl;
}
};
class child: public base{
public:
void aprint(){
cout << "child aprint" << endl;
}
};
int main(){
child a;
a.aprint();//打印child aprint
base * bp = &a;
bp->aprint();//打印base aprint
return 0;
}
2、虚函数的调用
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
class base{
public:
//virtual void aprint(){
void aprint(){
cout << "base aprint" << endl;
}
void bprint(){
cout << "base bprint" << endl;
aprint();
}
virtual void cprint(){
cout << "base cprint" << endl;
}
};
class child: public base{
public:
virtual void aprint(){
cout << "child aprint" << endl;
}
void cprint(){
cout << "child cprint" << endl;
}
};
class child1: public child{
private:
void aprint(){
cout << "child1 aprint" << endl;
}
void bprint(){
cout << "child1 bprint" << endl;
cprint();
}
void cprint(){
cout << "child1 cprint" << endl;
}
};
int main(){
child a;
a.bprint();//打印base bprint base aprint
base * bp = &a;
bp->aprint();//打印base aprint
bp->cprint();//打印child cprint
child1 c1;
child* cp = &c1;
bp = &c1;
bp->aprint();//打印base aprint
cp->aprint();//打印child1 aprint;
bp->cprint();//打印child1 cprint
//同时注意,chilid1类中的aprint和cprint均是私有函数,也即父类可以通过虚函数特性去直接调用到子类的私有虚函数
return 0;
}
从以上代码可以发现,由于chilid1类中的aprint和cprint均是私有函数,但是仍然通过父类指针实现了多态调用,也即父类可以通过虚函数特性去直接调用到子类的私有虚函数。
3、虚函数与继承
若父类中函数声明为虚函数(即函数前面带virtual关键字),则子类中不管同名函数(包括相同参数)是否声明为虚函数,都为虚函数。例如2中,由于在类child中,aprint()为虚函数,所以child1::aprint()即使没有加virtual声明为虚函数,它仍然是一个虚函数。
4、非虚函数中调用虚函数与非虚函数的区别
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
class base{
public:
void aprint(){
cout << "base aprint" << endl;
}
void bprint(){
cout << "base bprint" << endl;
aprint();
cprint();
}
virtual void cprint(){
cout << "base cprint" << endl;
}
};
class child: public base{
public:
virtual void aprint(){
cout << "child aprint" << endl;
}
virtual void cprint(){
cout << "child cprint" << endl;
}
};
int main(){
child a;
a.bprint();
//打印base bprint base aprint child cprint
return 0;
}
由于bprint()是非虚函数,当其被调用时,实际调用的是base.bprint()。由于在base类中,aprint为非虚函数,所以在base.bprint()中调用aprint时,会去base类的函数表中查找aprint的函数地址,所以实际调用的是base类中定义的aprint(即使此时在子类中aprint定义为虚函数);而cprint则因为在基类中定义为虚函数,所以会去子类child的函数表中查找函数地址,因此打印child cprint。