小编典典

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

all

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

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


阅读 64

收藏
2022-07-16

共1个答案

小编典典

虚拟可能有默认值。基类中的默认值不会被派生类继承。

使用哪个默认值——即,基类’或派生类’——由用于调用函数的静态类型决定。如果通过基类对象、指针或引用调用,则使用基类中表示的默认值。相反,如果您通过派生类对象、指针或引用调用,则使用派生类中表示的默认值。标准报价下面有一个例子可以证明这一点。

一些编译器可能会做一些不同的事情,但这就是 C03 和 C11 标准所说的:

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这里使用 s 而不是classes
只是为了简洁——除了默认可见性之外,几乎在所有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
2022-07-16