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

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (25)

如果我声明一个基类(或接口类)并为它的一个或多个参数指定默认值,派生类是否必须指定相同的默认值?如果没有,哪些默认值将在派生类中显示?

如何在不同的编译器之间处理这个问题,以及在这个场景中对“推荐”实践的任何输入。

提问于
用户回答回答于

虚拟者可能有默认值。基类中的默认值不是由派生类继承的。

使用哪种默认值--即基类‘或派生类’--取决于用于调用函数的静态类型。如果通过基类对象、指针或引用进行调用,则使用基类中表示的默认值。相反,如果通过派生类对象进行调用,则使用派生类中表示的缺省值指针或引用。在“标准引号”下面有一个示例说明了这一点。

有些编译器可能会做一些不同的事情,但C++03和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()
}

下面是一个示例程序,用于演示获取哪些默认值。我在用struct在这里而不是class只是为了简洁--classstruct除了默认的可见性外,几乎在所有方面都是完全相同的。

#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;
}

这个程序的输出(在MSVC 10和GCC 4.4上)是:

Base 42
Der 42
Der 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::foo 1 B::foo 2 B::foo 1

扫码关注云+社区