是否可以重载(影子)虚函数?

Is it possible to overload (shadow) a virtual function?

我想隐藏一个基础class的虚函数,并引入一个新的具有相同名称和相同签名的虚函数,除了return类型。

类似于:

struct A {
  virtual int f() = 0;              // Newly introduced method: A::f.
};
struct B: public A {
  int f() final { return 1; }       // Overriding A::f.
};
struct C: public B {
  virtual double f() = 0;           // Newly introduced method C::f. It shadows A::f
};
struct D: public C {
  double f() final { return 2.0; }  // Overriding C::f.
};

我希望它的行为如下:

D d;
ASSERT( static_cast<D&>(d).f() == 2.0 );
ASSERT( static_cast<C&>(d).f() == 2.0 );
ASSERT( static_cast<B&>(d).f() == 1 );
ASSERT( static_cast<A&>(d).f() == 1 );

有可能实现吗?

任何版本的 C++ 标准都可以。

不更改函数签名(return 类型不是其中的一部分)就不可能重载。但是由于默认的函数参数,我们可以有不同的签名,但仍然使用相同数量的参数调用。使用像 C++20 的 std::type_identity 之类的东西(虽然可以在任何标准中轻松实现),曾经可以写

struct A {
  virtual int f(std::type_identity<int> = {}) = 0;
};
struct B: public A {
  int f(std::type_identity<int> = {}) final { return 1; }
};
struct C: public B {
  virtual double f(std::type_identity<double> = {}) = 0;
};
struct D: public C {
  double f(std::type_identity<double> = {}) final { return 2.0; }
};

每个重载现在都标有其 return 类型,从而赋予每个重载不同的签名。但是默认参数 {} 可以通过 f() 调用它们。由于名称隐藏,空参数列表的重载集没有冲突。

经过这些修改,your set of assertions now passes

如果你不让 C 直接继承自 B,而是引入继承自 BDE,你可以有不同的 f()s 并用 static_casts 消除它们之间的歧义。

struct A {
  virtual int f() = 0;              // Newly introduced method: A::f.
};

struct B: public A {
  int f() override final { return 1; }       // Overriding A::f.
};

struct C {
  virtual double f() = 0;           // Newly introduced method C::f
};

struct D: public C {
  double f() override final { return 2.0; }  // Overriding C::f.
};

struct E : public B, public D { // inherit from both B and D
};
int main() {
    E foo;
    std::cout << static_cast<A&>(foo).f() << '\n'; // 1
    std::cout << static_cast<B&>(foo).f() << '\n'; // 1
    std::cout << static_cast<C&>(foo).f() << '\n'; // 2
    std::cout << static_cast<D&>(foo).f() << '\n'; // 2
}