虚函数可以具有默认参数吗?

如果我声明一个基类(或接口类),并为其一个或多个参数指定默认值,那么派生类是否必须指定相同的默认值;如果没有,则默认值将出现在派生类中吗?

附录:我也对在不同的编译器中如何处理此问题以及在这种情况下对“推荐”实践的任何投入感兴趣。


拉丁的传说
浏览 1175回答 3
3回答

狐的传说

虚拟机可能具有默认设置。基类中的默认值不被派生类继承。使用哪个默认值(即基类或派生类)取决于用于调用函数的静态类型。如果通过基类对象,指针或引用进行调用,则使用基类中表示的默认值。相反,如果通过派生类对象,指针或引用进行调用,则使用派生类中表示的默认值。在“标准”引号下有一个示例对此进行了说明。一些编译器可能会做一些不同的事情,但这就是C ++ 03和C ++ 11标准所说的:(编辑:C ++ 11标准说的完全一样)8.3.6.10:虚函数调用(10.3)在虚函数的声明中使用默认参数,该声明由表示对象的指针或引用的静态类型确定。派生类中的重写函数不会从其重写的函数中获取默认参数。[例:struct A {&nbsp; virtual void f(int a = 7);};struct B : public A {&nbsp; void f(int a);};void m(){&nbsp; B* pb = new B;&nbsp; A* pa = pb;&nbsp; pa->f(); //OK, calls pa->B::f(7)&nbsp; 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)&nbsp;{&nbsp;&nbsp; &nbsp; stringstream ss;&nbsp; &nbsp; ss << "Base " << n;&nbsp; &nbsp; return ss.str();}string Der::Speak(int n){&nbsp; &nbsp; stringstream ss;&nbsp; &nbsp; ss << "Der " << n;&nbsp; &nbsp; return ss.str();}int main(){&nbsp; &nbsp; Base b1;&nbsp; &nbsp; Der d1;&nbsp; &nbsp; Base *pb1 = &b1, *pb2 = &d1;&nbsp; &nbsp; Der *pd1 = &d1;&nbsp; &nbsp; cout << pb1->Speak() << "\n"&nbsp; &nbsp; // Base 42&nbsp; &nbsp; &nbsp; &nbsp; << pb2->Speak() << "\n"&nbsp; &nbsp; &nbsp;// Der 42&nbsp; &nbsp; &nbsp; &nbsp; << pd1->Speak() << "\n"&nbsp; &nbsp; &nbsp;// Der 84&nbsp; &nbsp; &nbsp; &nbsp; << endl;}该程序的输出(在MSVC10和GCC 4.4上)为:Base 42Der 42Der 84

慕斯王

他在这个问题上说的第一件事就是不要做。是的,您可以指定更详细的默认参数。它们的工作方式与虚拟功能不同。在对象的动态类型上调用虚拟函数,而默认参数值基于静态类型。给定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

ABOUTYOU

这是一个坏主意,因为您获得的默认参数将取决于对象的静态类型,而virtual分派到的函数将取决于动态类型。也就是说,当您使用默认参数调用函数时,无论该函数是否存在,默认参数都会在编译时被替换virtual。@cppcoder在他的[已关闭] 问题中提供了以下示例:struct A {&nbsp; &nbsp; virtual void display(int i = 5) { std::cout << "Base::" << i << "\n"; }};struct B : public A {&nbsp; &nbsp; virtual void display(int i = 9) override { std::cout << "Derived::" << i << "\n"; }};int main(){&nbsp; &nbsp; A * a = new B();&nbsp; &nbsp; a->display();&nbsp; &nbsp; A* aa = new A();&nbsp; &nbsp; aa->display();&nbsp; &nbsp; B* bb = new B();&nbsp; &nbsp; bb->display();}产生以下输出:Derived::5Base::5Derived::9借助上面的解释,很容易看出原因。在编译时,编译器将从指针的静态类型的成员函数中替换默认参数,从而使该main函数等效于以下内容:&nbsp; &nbsp; A * a = new B();&nbsp; &nbsp; a->display(5);&nbsp; &nbsp; A* aa = new A();&nbsp; &nbsp; aa->display(5);&nbsp; &nbsp; B* bb = new B();&nbsp; &nbsp; bb->display(9);
打开App,查看更多内容
随时随地看视频慕课网APP