函数参数的继承
问题描述:
我想知道如何正确地重写派生类与派生函数参数的功能?
例如函数参数的继承
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);
};
答
您可以使用返回值/参数的派生/基类的基数称为协变返回类型和逆变参数。
在C++中,virtual
指针的引用和指针返回类型在派生类型中具有协变重载;您可以在派生类型中返回一个更受限制的(指针或引用)到基类返回类型。
在C++中不支持参数变异,其中基本接口中的参数Derived*
替换为派生参数中的Base*
参数,但您可以通过重载和重写来模拟它。
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
是返回类型中的协方差的一个例子。编译器会自动为我们做这个事情,在这种情况下,我们只是基于指针和引用类型heirarchy来做协方差。
contra_example
是参数类型的反例的例子。 ptr
,参数为contra_example
,在DerivedInterface
的情况下可以是任何Value*
。基本接口要求它是一个DerivedValue*
。
我们都可以覆盖基本contra_example
,然后转发给内部“比较能接受”的实施是一个超载在DerivedInterface
。
派生接口是更宽容比基部接口,它提供了保证至少一样好,或者比原来的不更好。
现在让我们回到你的问题。首先,不,编译器不会为你做。
其次,你的逻辑是有缺陷的。使用Liskov substitution principle,您的B
必须能够代替A
。
但你B
有更受限制合同上的参数f
比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;
}
这对应于您的示例。派生的接口更容许他们的(隐式输入)参数。
你可以跳过这个循环以获得支持协方差的只出错的参数,或者直接返回它们。
如果可能,请考虑将X传递给动态类型为B的A,该呼叫应该解析为什么? –
你不能这样做,因为它会是错的。不支持反方差,仅支持返回类型的协方差。 – Jarod42
@ Jarod42,但只有返回参考和指针和基准派生关系的协方差,它是协方差的一个子阵。 – Yakk