我想知道如何正確地重寫派生類與派生函數參數的功能?
例如函數參數的繼承
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);
};
我想知道如何正確地重寫派生類與派生函數參數的功能?
例如函數參數的繼承
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