亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

虛函數可以具有默認參數嗎?

虛函數可以具有默認參數嗎?

C++
拉丁的傳說 2019-11-08 12:55:55
如果我聲明一個基類(或接口類),并為其一個或多個參數指定默認值,那么派生類是否必須指定相同的默認值;如果沒有,則默認值將出現在派生類中嗎?附錄:我也對在不同的編譯器中如何處理此問題以及在這種情況下對“推薦”實踐的任何投入感興趣。
查看完整描述

3 回答

?
狐的傳說

TA貢獻1804條經驗 獲得超3個贊

虛擬機可能具有默認設置。基類中的默認值不被派生類繼承。


使用哪個默認值(即基類或派生類)取決于用于調用函數的靜態類型。如果通過基類對象,指針或引用進行調用,則使用基類中表示的默認值。相反,如果通過派生類對象,指針或引用進行調用,則使用派生類中表示的默認值。在“標準”引號下有一個示例對此進行了說明。


一些編譯器可能會做一些不同的事情,但這就是C ++ 03和C ++ 11標準所說的:


(編輯:C ++ 11標準說的完全一樣)


8.3.6.10:

虛函數調用(10.3)在虛函數的聲明中使用默認參數,該聲明由表示對象的指針或引用的靜態類型確定。派生類中的重寫函數不會從其重寫的函數中獲取默認參數。[例:


struct A {

  virtual void f(int a = 7);

};

struct B : public A {

  void f(int a);

};

void m()

{

  B* pb = new B;

  A* pa = pb;

  pa->f(); //OK, calls pa->B::f(7)

  pb->f(); //error: wrong number of arguments for B::f()

}

—end example]

編輯這里是一個示例程序,以演示選擇哪些默認值。我使用的是struct這兒,而不是class簡單地為了簡潔ES - class并且struct是在除了默認的知名度幾乎所有的方式完全一樣。


#include <string>

#include <sstream>

#include <iostream>

#include <iomanip>


using std::stringstream;

using std::string;

using std::cout;

using std::endl;


struct Base { virtual string Speak(int n = 42); };

struct Der : public Base { string Speak(int n = 84); };


string Base::Speak(int n) 

    stringstream ss;

    ss << "Base " << n;

    return ss.str();

}


string Der::Speak(int n)

{

    stringstream ss;

    ss << "Der " << n;

    return ss.str();

}


int main()

{

    Base b1;

    Der d1;


    Base *pb1 = &b1, *pb2 = &d1;

    Der *pd1 = &d1;

    cout << pb1->Speak() << "\n"    // Base 42

        << pb2->Speak() << "\n"     // Der 42

        << pd1->Speak() << "\n"     // Der 84

        << endl;

}

該程序的輸出(在MSVC10和GCC 4.4上)為:


Base 42

Der 42

Der 84


查看完整回答
反對 回復 2019-11-08
?
慕斯王

TA貢獻1864條經驗 獲得超2個贊

他在這個問題上說的第一件事就是不要做。


是的,您可以指定更詳細的默認參數。它們的工作方式與虛擬功能不同。在對象的動態類型上調用虛擬函數,而默認參數值基于靜態類型。


給定


class A {

? ? virtual void foo(int i = 1) { cout << "A::foo" << i << endl; }

};

class B: public A {

? ? virtual void foo(int i = 2) { cout << "B::foo" << i << endl; }

};

void test() {

A a;

B b;

A* ap = &b;

a.foo();

b.foo();

ap->foo();

}

您應該得到A :: foo1 B :: foo2 B :: foo1


查看完整回答
反對 回復 2019-11-08
?
ABOUTYOU

TA貢獻1812條經驗 獲得超5個贊

這是一個壞主意,因為您獲得的默認參數將取決于對象的靜態類型,而virtual分派到的函數將取決于動態類型。


也就是說,當您使用默認參數調用函數時,無論該函數是否存在,默認參數都會在編譯時被替換virtual。


@cppcoder在他的[已關閉] 問題中提供了以下示例:


struct A {

    virtual void display(int i = 5) { std::cout << "Base::" << i << "\n"; }

};

struct B : public A {

    virtual void display(int i = 9) override { std::cout << "Derived::" << i << "\n"; }

};


int main()

{

    A * a = new B();

    a->display();


    A* aa = new A();

    aa->display();


    B* bb = new B();

    bb->display();

}

產生以下輸出:


Derived::5

Base::5

Derived::9

借助上面的解釋,很容易看出原因。在編譯時,編譯器將從指針的靜態類型的成員函數中替換默認參數,從而使該main函數等效于以下內容:


    A * a = new B();

    a->display(5);


    A* aa = new A();

    aa->display(5);


    B* bb = new B();

    bb->display(9);


查看完整回答
反對 回復 2019-11-08
  • 3 回答
  • 0 關注
  • 1229 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號