3 回答

TA貢獻1862條經驗 獲得超7個贊
在某些情況下,是的,只要返回類型與原始返回類型協變,派生類使用不同的返回類型覆蓋虛擬函數是合法的。例如,考慮以下內容:
class Base {
public:
virtual ~Base() {}
virtual Base* clone() const = 0;
};
class Derived: public Base {
public:
virtual Derived* clone() const {
return new Derived(*this);
}
};
在這里,Base定義了一個純虛擬函數clone,該函數返回a Base *。在派生的實現中,此虛擬函數使用的返回類型重寫Derived *。盡管返回類型與基本類型不同,但這是絕對安全的,因為任何時候您都會編寫
Base* ptr = /* ... */
Base* clone = ptr->clone();
調用to clone()始終會返回指向Base對象的指針,因為即使返回a Derived*,該指針也可以隱式轉換為a,Base*并且該操作定義明確。
更一般而言,函數的返回類型從不視為其簽名的一部分。您可以使用任何返回類型覆蓋成員函數,只要返回類型是協變的即可。

TA貢獻1744條經驗 獲得超4個贊
是。只要它們是協變的,返回類型就可以不同。C ++標準對此進行了描述(第10.3 / 5節):
覆蓋函數的返回類型應與覆蓋函數的返回類型相同或與函數的類協變。如果一個函數D::f覆蓋某個函數B::f,則滿足以下條件的函數的返回類型將是協變的:
兩者都是指向類或指向類98的指針)
返回類型B::f為的類與D::f或返回類型為的類相同,是返回類型為的類的明確的直接或間接基類,D::f并且可以在中訪問D
指針或引用都具有相同的cv限定,并且返回類型的類類型D::f具有與等于或小于返回類型的類類型相同的cv限定B::f。
腳注98指出“不允許使用指向類的多級指針或指向類的多級指針”。
簡而言之,如果D是的子類型B,則in中的函數的返回類型D需要是中的函數的返回類型的子類型B。最常見的示例是當返回類型本身基于D和時B,但不一定必須如此??紤]一下,在這里我們有兩個單獨的類型層次結構:
struct Base { /* ... */ };
struct Derived: public Base { /* ... */ };
struct B {
virtual Base* func() { return new Base; }
virtual ~B() { }
};
struct D: public B {
Derived* func() { return new Derived; }
};
int main() {
B* b = new D;
Base* base = b->func();
delete base;
delete b;
}
之所以起作用,是因為任何的調用者func都希望有一個Base指針。任何Base指針都可以。因此,如果D::func保證總是返回一個Derived指針,那么它將始終滿足祖先類提出的約定,因為任何Derived指針都可以隱式轉換為Base指針。因此,呼叫者將始終得到他們所期望的。
除了允許返回類型改變之外,某些語言還允許覆蓋函數的參數類型改變。當他們這樣做時,它們通常需要保持不變。也就是說,如果B::f接受Derived*,則將D::f允許接受Base*。后代可以放寬接受的條件,嚴格要求返回的條件。C ++不允許參數類型相反。如果更改參數類型,則C ++會將其視為全新功能,因此您開始陷入重載和隱藏狀態。有關此主題的更多信息,請參見Wikipedia中的協方差和逆方差(計算機科學)。
- 3 回答
- 0 關注
- 894 瀏覽
添加回答
舉報