【问题标题】:Inheritance of function parameter函数参数的继承
【发布时间】:2017-10-05 15:46:05
【问题描述】:

我想知道如何使用派生函数参数正确覆盖派生类的函数?
例如

struct X;
struct Y:X
struct Z:X

class A {
    public:
      int f(int, X);    
};

class B : A{
    public:
       int f(int, Y);
};

class C : A{
    public:
       int f(int, Z);
};

【问题讨论】:

  • 如果可能,考虑将 X 传递给动态类型为 B 的 A,调用应解析为什么?
  • 你不能这样做,因为那是错误的。不支持反方差,仅支持返回类型的协方差。
  • @Jarod42 但只有返回引用和指针以及基派生关系的协方差,这是协方差的一个子项。
  • wiKon,您的代码没有覆盖,因为覆盖仅发生在 virtual 方法中,超出了您对反方差的要求。当他们无法用代码表达他们想要的东西时,真的很难读懂他们的想法。始终尝试创建一个有效的编译示例,然后对代码进行最少的编辑以描述您想要工作的内容。

标签: c++ inheritance overriding


【解决方案1】:

您可以用派生类/基类替换返回值/参数的想法称为协变返回类型和逆变参数。

在 C++ 中,virtual 指针的引用和指针返回类型在派生类型中具有协变重载;您可以在派生类型中返回一个更受限制(指针或引用)的基返回类型。

C++ 不支持参数的逆变,即用派生的 Base* 参数替换基接口中的 Derived* 参数,但您可以通过重载和覆盖来模拟它。

struct BaseValue {};
struct DerivedValue:BaseValue {};
struct MoreDerivedValue:DerivedValue {};

struct BaseInterface {
  virtual void contra_example( DerivedValue* ptr ) = 0;
  virtual DerivedValue* co_example() = 0;
  virtual ~BaseInterface() {}
};

struct DerivedInterface:BaseInterface {
  virtual void contra_example( DerivedValue* ptr ) override final {
    contra_example( static_cast<Value*>( ptr ) );
  }
  void contra_example( Value* ptr ) override = 0;

  virtual MoreDerivedValue* co_example() override = 0;
};

co_example 是返回类型协方差的一个示例。如果我们只是根据指针和对类型层次结构的引用进行协变,编译器会自动为我们执行此操作。

contra_example 是参数类型逆变的一个例子。 ptrcontra_example 的参数,在DerivedInterface 的情况下可以是任何Value*。基本接口要求它是DerivedValue*

我们可以覆盖基础contra_example,然后转发到我们内部的“更接受”实现,这是DerivedInterface 中的一个重载

派生接口比基接口更宽松,它提供的保证至少与原始接口一样好,或更好


现在让我们回到您的问题。首先,不,编译器不会为你做。

第二,你的逻辑有缺陷。使用Liskov substitution principle,您的B 必须能够替换A

但是你的Bf 的论点比A 有一个更受限制的合同。 A 需要 X 参数,B 不仅需要 X 还需要 Y

struct X1{};
struct X2{};
struct Y:X1,X2{};

struct A {
  virtual void foo( Y* ) = 0;
  virtual ~A() {}
}
struct B1:A {
  virtual void foo( Y* ptr ) final override { foo( static_cast<X1*>(ptr) ); }
  virtual void foo( X1* ) = 0;
}
struct B2:A {
  virtual void foo( Y* ptr ) final override { foo( static_cast<X2*>(ptr) ); }
  virtual void foo( X2* ) = 0;
}

这对应于您的示例。派生接口对它们的(隐式输入)参数更加宽容。

您可以跳过箍来获得支持协方差的仅输出参数,或者简单地返回它们。

【讨论】:

    猜你喜欢
    • 2021-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多