簡體   English   中英

具有不同參數類型的虛函數

[英]Virtual functions with different argument types

我試圖理解虛函數是如何工作的,我陷入了某個角色。

我寫過這個小程序:

class First
{
public:
    virtual void f(int a) 
    {
        cout << "First!" << endl;
        cout << a << endl;
    }
};

class Second : public First
{
public:
    void f(int a) {
        cout << "Second!" << endl;
        cout << a << endl;
    }
};

void main() {
    Second s;
    First *p = &s;
    p->f(5);
    First n;
    p = &n;
    p->f(3);
    _getch();
}

此代碼導致:

Second!
5
First!
3

但是,如果我將Second::f()函數中的int更改為其他類型,如下所示:

class First
{
public:
    virtual void f(int a) {
        cout << "First!" << endl;
        cout << a << endl;
    }
};

class Second : public First
{
public:
    void f(double a) { //double instead int here!
        cout << "Second!" << endl;
        cout << a << endl;
    }
};

void main() {
    Second s;
    First *p = &s;
    p->f(5);
    First n;
    p = &n;
    p->f(3);
    _getch();
}

我的程序從不調用Second::f() ,我得到的結果如下:

First!
5
First!
3

有人可以向我解釋為什么會這樣嗎?

當使用虛函數調度時,所謂的“最終覆蓋”就是被調用的東西。 對於甚至覆蓋繼承的虛函數的函數,它必須滿足一些條件:

如果虛擬成員函數vf在類BaseDerived類中聲明,直接或間接從Base Derived ,則具有相同名稱的成員函數vfparameter-type-list (8.3.5),cv-qualification和聲明了Base::vf refqualifier(或不存在),然后Derived::vf也是虛擬的(無論是否聲明)並且它覆蓋 Base::vf

- ISO / IEC 14882:2001(E)§10.3(大膽強調我的)

很簡單,在你的第二個例子中的參數列表Second::f(double)從不同的First::f(int)所以Second::f(double) (自動),虛擬和覆蓋First::f(int)

C ++ 11關鍵字override聲明了一個方法覆蓋繼承的虛方法的意圖,以便編譯器可以告訴您何時不這樣做。 例如,如果你這樣做了:

void f(double a) override {

編譯器會給你這個診斷通知你它實際上沒有覆蓋任何東西,它甚至告訴你為什么它沒有( “在第一個參數類型不匹配('int'與'double')” ):

main.cpp:15:18: error: non-virtual member function marked 'override' hides virtual member function
void f(double a) override { //double instead int here!
                 ^
main.cpp:7:14: note: hidden overloaded virtual function 'First::f' declared here: type mismatch at 1st parameter ('int' vs 'double')
virtual void f(int a) {
             ^

事實上,派生類不會重新聲明基類的虛函數。 他們重新定義了它們,在C ++方面意味着覆蓋基類的虛函數的定義。

在第二個示例中,派生類聲明了一個新的非虛函數(因為函數說明符virtual不存在),其名稱與基類中虛函數的名稱相同。 新聲明的函數隱藏了基類中虛函數的聲明。

在此代碼段中

Second s;
First *p = &s;
p->f(5);

指針p的靜態類型是First 因此,編譯器查看First類中聲明的虛函數表,並找到指向First類中聲明的函數的指針。 此指針不會被派生類中的虛函數的地址覆蓋,因為派生類沒有覆蓋基類函數。

如果你會寫例如

Second s;
Second *p = &s;
^^^^^^
p->f(5);

然后將調用派生類中聲明的非虛函數。

在第二段代碼中,Second繼承了一個名為f()的虛函數,並有自己的函數f()。

現在,因為所有調用都是從First(或First指向的對象)完成的,所以它的工作原理如下:當你從First對象調用時,很明顯將調用First中的函數。 現在,當你從指向First的第二個對象調用時,因為f()是虛擬的,“編譯器”[請看下面的注釋]在實際的類中搜索它(這是第二個)但是從那里開始是沒有匹配void f(int)的函數然后從First獲取一個函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM