【问题标题】:Is it possible to overload (shadow) a virtual function?是否可以重载(阴影)虚函数?
【发布时间】:2021-04-22 18:17:29
【问题描述】:

我想隐藏一个基类的虚函数,并引入一个具有相同名称和相同签名的新虚函数,但返回类型除外。

类似:

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++ 标准都可以。

【问题讨论】:

  • 一般来说,你不能拥有具有相同签名和不同返回类型的函数。
  • 如果您将A::f 函数设为模板,然后将其专门用于子类BD,也许它会起作用?这取决于用例和您需要解决的实际问题(请始终直接询问)。
  • @Someprogrammerdude 但是即使从模板生成,如果两个函数声明仅在返回类型上有所不同,它将不起作用。

标签: c++ inheritance overriding overloading virtual-functions


【解决方案1】:

如果不更改函数签名(返回类型不是其中的一部分),重载是不可能的。但是由于默认的函数参数,我们可以有不同的签名,但仍然使用相同数量的参数调用。使用像 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; }
};

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

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

【讨论】:

  • 谢谢,这完美无缺!需要std::type_identity 吗?即使没有,代码似乎也能编译。
  • @Helloer - 我不完全确定您所说的“没有”是什么意思。我将它用作一种普遍廉价的标签类型,可以很容易地默认初始化。如果你做了int = {}double = {} 我想这可能会起作用,但是当你处理初始化和/或按值传递的类型时会发生什么?标签总是很便宜。
  • 哦,我现在明白了,你是对的。出于某种奇怪的原因,我的大脑认为您使用的是std::type_identity_t
【解决方案2】:

如果你不让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
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-29
    • 2021-10-15
    • 2014-10-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多