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則是正常調用基類的函數。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章