为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

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 关注
  • 1174 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信