C++ 用不同方法的签名覆盖理解

C++ override understanding with different method's signatures

我希望在 C++ 中,如果方法在 Base 和 Derived classes 中具有相同的签名,包括名称、参数和 return 类型,那么您可以覆盖方法。

如果我尝试编译这样的东西,我会在两种方法(get、get2)上都失败:

#include <iostream>

class A
{
public:
  A() {}
  virtual int get() { return 0; }
  virtual int *get2() { return 0; }
};

class B : public A
{
public:
  B() {}
  float get() override { return 0.f; }
  float *get2() override { return 0.f; }
};

using namespace std;

int main()
{
  A a;
  B b;
  cout << a.get() << endl;
  cout << b.get() << endl;

  return 0;
}

我有代码:

#include <iostream>
class C
{
public:
  C(){};
  virtual int get() { return 0; };
};

class D : public C
{
public:
  D(){};
  int get() override { return 1; };
};

class E : public D
{
public:
  E(){};
  virtual int get() { return 2; };
};

class A
{
public:
  A() { d = new D(); }
  virtual D *get() { return dynamic_cast< D * >(d); }
  D *d;
};

class B : public A
{
public:
  B() { d = new E(); }
  E *get() override { return dynamic_cast< E * >(d); }
};

class Z : public A
{
public:
  Z() { d = new E(); }
  C *get() override { return dynamic_cast< C * >(d); }
};

using namespace std;

int main()
{
  A a;
  B b;
  Z z;
  cout << a.get()->get() << endl;
  cout << b.get()->get() << endl;
  cout << z.get()->get() << endl;

  return 0;
}

而且我预计 classes(B 和 Z)都会失败。但是我只在 class Z 上失败了。有人可以解释一下吗?

如果基 class 声明了一个 return 是指向 class 的指针或引用的虚函数,则重写虚函数 可以 return 指向 class 类型的指针或引用,派生自基函数声明的 return 类型。
这被称为“协变 return 类型”。

示例:

class Object {};
class Derived : public Object {};

class Interface {
public:
    virtual Object* get() = 0;
};

class Impl : public Interface {
public:
    Derived* get() override { return nullptr; } // OK
};

如果你有一个指向接口的指针并调用 get(),你会得到一个 Object*,因为 Derived* 由于继承可以转换为 Object*。

但是,如果您有一个 Impl 实例,并且直接在其上调用 get(),则可以受益于更具体的 return 类型。 (毕竟,如果您使用的是 impl 类型而不是其接口,那么了解更多关于实现的信息不是问题。)

按照标准:

[class.virtual] 11.6.2.8: The return type of an overriding function shall be either identical to the return type of the overridden function or covariant with the classes of the functions. If a function D::f overrides a function B::f, the return types of the functions are covariant if they satisfy the following criteria:

  • both are pointers to classes, both are lvalue references to classes, or both are rvalue references to classes
  • the class in the return type of B::f is the same class as the class in the return type of D::f, or is an unambiguous and accessible direct or indirect base class of the class in the return type of D::f
  • both pointers or references have the same cv-qualification and the class type in the return type of D::f has the same cv-qualification as or less cv-qualification than the class type in the return type of B::f.