重載虛函數的相關問題


我們先看以下三個共同的術語來區分:

①要正常f()進行重載(overload)是表示,在同樣的作用域中定義還有一個同樣的名字(f)的函數,而且這個函數與f()有着不同的參數個數和參數類型。當程序調用函數f()時。編譯器將會依據實際提供的參數來選擇最匹配的函數。

②對虛函數f()進行覆蓋(override)是表示,在派生類中定義一個同樣的名字(f)的函數。而且這個函數的參數個數和參數類型與f()是同樣的。

③對外層作用域(基類、外部類或者名字空間)中的函數f()進行隱藏(hide)是表示在內層作用域(派生類、嵌套類或者嵌套名字空間)中定義還有一個同樣名字(f)的函數,這將隱藏外層作用域中同樣名字的函數。

以下看一個樣例:

class Base

{

public:

   virtual void f(int);

   virtual void f(double);

   virtual void g(int i = 10);

};

void Base::f(int)

{

   cout << "Base::f(int)" << endl;

}

void Base::f(double)

{

   cout << "Base::f(double)" << endl;

}

void Base::g(int i)

{

   cout << i << endl;

}

class Derived:public Base

{

public:

   void f(complex<double>);

   void g(int i = 20);

};

void Derived::f(complex<double> a)

{

   cout << "Derived::f(complex)" << endl;

}

void Derived::g(int i)

{

   cout << "Derived::g()" << i << endl;

}

int main()

{

   Base b;

   Derived d;

   Base* pb = new Derived;

   b.f(1.0);

   d.f(1.0);

   pb->f(1.0);

   b.g();

   d.g();

   pb->g();

   delete pb;

   return 0;

}

①“delete pb;”是不安全的

我們通常應該將基類的析構函數定義為虛函數。

在上面的代碼中,我們是通過指向基類的指針來刪除派生類的對象,而在基類中並未定義虛析構函數,那么這就會產生問題,上面代碼將調用錯誤的析構函數。

②Derived::f不是重載函數

在Derived類中並非對Base::f進行重載,而是隱藏了這個函數。

這個差別是非常重要的。由於它意味着在Derived的作用域中,Base::f(int)和Base::f(double)將是不可見的。假設要將Base::f這個名字引入到Derived的作用域中。正確地方法是使用using聲明語句------“using Base::f"。

③我們永遠都不要去改變所覆蓋的基類函數中的默認參數值

函數Derived::g覆蓋了Base::g,但卻改變了默認參數值void g(int i = 20);

以下分析上面的程序的輸出結果:

b.f(1.0);調用Base::f(double),這與程序猿所期望的是一致的。

d.f(1.0);將調用Derived::f(complex<double>).由於Base::f(int)和Base::f(double)被Derived::f(complex<double>)隱藏了。

我們可能希望這行代碼會去調用Base::f(double),但在這樣的情況下是不會的,並且編譯器甚至不會報錯。由於幸運的是,complex<double>可以提供從double來的隱式轉換,因此編譯器會將這個調用解釋為Derived::f(complex<double>(1.0)).

pb->f(1.0);盡管指針Base  * pb指向的是一個Derived對象,但上面這行代碼調用的卻是Base::f(double),這是由於重載解析僅僅是作用於靜態類型(這里是Base),而不是動態類型(這里是Derived)。同理,函數調用”pb->f(complex<double>(1.0))“將無法通過編譯,這是由於在Base的接口中沒有符合要求的函數。

b.g();將輸出”10“,調用了Base::g(int).

d.g();將輸出”Derived::g()20"。由於這僅僅是調用了Derived::g(int),而這個函數的默認參數值是20.

pb->g();這將輸出“Derived::g()10"。我們要記住的是,,在相同的函數重載。默認參數是靜態類型的對象從(這是Base)。由此得到的默認值它是10.然而。因為該功能是一個虛函數,因此,該函數的實際動態類型由對象稱為(這是Derived)決定。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM