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

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

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);
- 3 回答
- 0 關注
- 1229 瀏覽
添加回答
舉報