C++中的虚函数
- 1.题目
- 2.虚函数
-
- 2.0 无继承
- 2.1 一般继承
-
- 2.1.1 无虚函数覆盖
- 2.1.2 有虚函数覆盖
- 2.2 多重继承
-
- 2.2.1 无虚函数覆盖
- 2.2.2 有虚函数覆盖
- 3.参考链接
- 4.又一道虚函数题目
1.题目
先看一下源代码,如下:
#include <iostream>
using namespace std;class A
{
public:void virtual print(){
cout << "A" << endl;}
};class B : public A
{
public:void virtual print(){
cout << "B" << endl;}
};int main()
{
A* pA = new A();//父类指针pA->print();//父类指针子类函数B* pB = (B*)pA;//强制类型转换pB->print();//子类指针父类函数delete pA, pB;//pA = new B();//父类指针声明子类对象pA->print();//父类指针pB = (B*)pA;//pB->print();//子类指针return 0;
}
程序的输出:
A
A
B
B
2.虚函数
以下出现的所有函数都是虚函数
虚函数表:类中有虚函数,该类实例出的对象会有一个虚函数表
2.0 无继承
类Base如下:
类 | 函数1 | 函数2 | 函数3 |
---|---|---|---|
Base | +f():void | +g():void | +h():void |
对于实例 Base b; 的虚函数表如下:
地址 | 函数1 | 函数2 | 函数3 |
---|---|---|---|
&b | Base::f() | Base::g() | Base::h() |
2.1 一般继承
2.1.1 无虚函数覆盖
类 | 函数1 | 函数2 | 函数3 |
---|---|---|---|
父类Base | +f():void | +g():void | +h():void |
子类Derive | +f1():void | +g1():void | +h1():void |
对于 b=new Base(); 实例的虚函数表:不需要管b是谁的
地址 | 函数1 | 函数2 | 函数3 |
---|---|---|---|
&b | Base::f() | Base::g() | Base::h() |
对于 d=new Derive(); 实例的虚函数表:不需要管d是谁的
地址 | 函数1 | 函数2 | 函数3 | 函数4 | 函数5 | 函数6 |
---|---|---|---|---|---|---|
&d | Base::f() | Base::g() | Base::h() | Derive::f1() | Derive::g1() | Derive::h1() |
2.1.2 有虚函数覆盖
类 | 函数1 | 函数2 | 函数3 |
---|---|---|---|
父类Base | +f():void | +g():void | +h():void |
子类Derive | +f():void | +g1():void | +h1():void |
对于 d=new Derive(); 实例的虚函数表:不需要管d是谁的
地址 | 函数1 | 函数2 | 函数3 | 函数4 | 函数5 |
---|---|---|---|---|---|
&d | Derive::f() | Base::g() | Base::h() | Derive::g1() | Derive::h1() |
如上所示:子类中的虚函数会覆盖父类的虚函数,并且在虚函数表中将原父类的位置覆盖掉。
2.2 多重继承
2.2.1 无虚函数覆盖
类 | 函数1 | 函数2 | 函数3 |
---|---|---|---|
父类1Base1 | +f():void | +g():void | +h():void |
父类2Base2 | +f():void | +g():void | +h():void |
父类3Base3 | +f():void | +g():void | +h():void |
子类Derive | +f1():void | +g1():void |
对于 d=new Derive(); 实例的虚函数表:不需要管d是谁的
地址 | 函数1 | 函数2 | 函数3 | 函数4 | 函数5 |
---|---|---|---|---|---|
&d | Base1::f() | Base1::g() | Base1::h() | Derive::f1() | Derive::g1() |
- | Base2::f() | Base2::g() | Base2::h() | ||
- | Base3::f() | Base3::g() | Base3::h() |
子类实例中的虚函数会按照原来的顺序,仅仅放置在第一个继承的链表的最后方,保证寻址时的唯一性。
2.2.2 有虚函数覆盖
类 | 函数1 | 函数2 | 函数3 |
---|---|---|---|
父类1Base1 | +f():void | +g():void | +h():void |
父类2Base2 | +f():void | +g():void | +h():void |
父类3Base3 | +f():void | +g():void | +h():void |
子类Derive | +f():void | +g1():void |
对于 d=new Derive(); 实例的虚函数表:不需要管d是谁的
地址 | 函数1 | 函数2 | 函数3 | 函数4 |
---|---|---|---|---|
&d | Derive::f() | Base1::g() | Base1::h() | Derive::g1() |
- | Derive::f() | Base2::g() | Base2::h() | |
- | Derive::f() | Base3::g() | Base3::h() |
会把每一个父类中覆盖的虚函数都替换掉。
3.参考链接
1.C++虚函数详解(你肯定懂了)
4.又一道虚函数题目
代码如下:
#include <iostream>
using namespace std;
struct Base{
int i;virtual int f(){
cout<<"a";return 1;}virtual const Base &f() const{
cout<<"b";return *this;//不知道翻坠这句是什么作用}int g(){
cout<<"c";return 3;}
};
struct Derive:Base{
int i;int f(){
cout<<"d";return 4;}const Base &f() const{
cout<<"e";return *this;}int f(int =0){
cout<<"f";return 6;}virtual int g(){
cout<<"g";return 7;}
};int main(){
Derive d;const Derive d_const;Base b,*p=&d;const Base *p_const=&d_const;b.f();p->f();p->g();p_const->f();d_const.f();
}
所以说上面的代码应该输出什么呢?
adcee
解释:
- b.f(); 基类对象直接调用基类的f()函数,输出a;
- p->f(); 派生类对象赋给基类的指针,由于f()在基类中是虚函数,根据基类指针指向的对象进行调用,因此调用派生类的int f()输出d;
- p->g();基类中g()不是虚函数,调用基类的g();
- p_const->f();常对象,又由于基类中声明为虚,同理用派生类中的函数;
- 同理。
更为经典的解释:
- 只有通过基类指针(或引用)间接指向派生类子类型时多态性才会起作用。
- 派生类的指针只调用自己的函数!
- 基类指针的函数调用,如果有virtual则根据多态性调用派生类的函数;
- 如果没有virtual则是正常调用基类的函数。