2017-10-05 123 views
2

我想知道如何正確地重寫派生類與派生函數參數的功能?
例如函數參數的繼承

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); 
}; 
+0

如果可能,請考慮將X傳遞給動態類型爲B的A,該呼叫應該解析爲什麼? –

+0

你不能這樣做,因爲它會是錯的。不支持反方差,僅支持返回類型的協方差。 – Jarod42

+0

@ Jarod42,但只有返回參考和指針和基準派生關係的協方差,它是協方差的一個子陣。 – Yakk

回答

2

您可以使用返回值/參數的派生/基類的基數稱爲協變返回類型和逆變參數。

在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更受限制合同上的參數fA一樣。 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; 
} 

這對應於您的示例。派生的接口更容許他們的(隱式輸入)參數。

你可以跳過這個循環以獲得支持協方差的只出錯的參數,或者直接返回它們。