21-0001 牛客网_一道虚函数练习题

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

解释:

  1. b.f(); 基类对象直接调用基类的f()函数,输出a;
  2. p->f(); 派生类对象赋给基类的指针,由于f()在基类中是虚函数,根据基类指针指向的对象进行调用,因此调用派生类的int f()输出d;
  3. p->g();基类中g()不是虚函数,调用基类的g();
  4. p_const->f();常对象,又由于基类中声明为虚,同理用派生类中的函数;
  5. 同理。

更为经典的解释:

  • 只有通过基类指针(或引用)间接指向派生类子类型时多态性才会起作用。
  • 派生类的指针只调用自己的函数!
  • 基类指针的函数调用,如果有virtual则根据多态性调用派生类的函数;
  • 如果没有virtual则是正常调用基类的函数。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章