我目前正在研究多態類型和賦值操作之間的相互作用。我主要關心的是某人是否可能嘗試將基類的值分配給派生類的對象,這會導致問題。檢測基類的派生指向派生類
從this answer我瞭解到,基類的賦值運算符總是被隱式定義的派生類的賦值運算符隱藏起來。所以對於賦值給一個簡單的變量,不正確的類型會導致編譯器錯誤。
class A { public: int a; };
class B : public A { public: int b; };
int main() {
A a; a.a = 1;
B b; b.a = 2; b.b = 3;
// b = a; // good: won't compile
A& c = b;
c = a; // bad: inconcistent assignment
return b.a*10 + b.b; // returns 13
}
分配的這種形式可能會導致inconcistent對象的狀態,但沒有編譯器警告和代碼看起來爲非作惡對我來說是第一次:但是,如果通過引用發生轉讓,這是不正確的一目瞭然。
是否有任何成熟的習慣用法來檢測此類問題?
我想我只能希望運行時檢測,如果我發現這樣一個無效的任務會拋出異常。我現在可以想到的最佳方法是基類中的用戶定義的assigment運算符,它使用運行時類型信息來確保this
實際上是指向基本實例的指針,而不是派生類,然後做一個手動的逐個成員的副本。這聽起來像是很多開銷,嚴重影響了代碼的可讀性。有什麼更容易嗎?
編輯:由於某些方法的適用性似乎取決於我想要做什麼,下面是一些細節。
我有兩個數學概念,說ring和field。每個領域都是一個環,但不是相反。每個實現有幾個實現,它們共享公共基類,即AbstractRing
和AbstractField
,後者從前者派生。現在我嘗試實現易於編寫的基於std::shared_ptr
的引用語義。所以我的Ring
類包含一個std::shared_ptr<AbstractRing>
持有它的實現,和一堆轉發到該方法。我想寫Field
從Ring
繼承,所以我不必重複這些方法。特定於某個字段的方法只需將指針投射到AbstractField
,我想這樣做是靜態地進行投射。我可以確保指針在施工時實際上是AbstractField
,但我擔心有人會將Ring
分配給Ring&
,這實際上是Field
,因此打破了我對所包含的共享指針的假定不變性。
這裏不是真正的問題,你有一個非抽象的基類嗎? – 2014-08-28 11:01:29
個人而言,我禁用了多態類型的複製構造函數和賦值運算符。繼承基礎多態性實際上不能很好地處理值類型。 – 2014-08-28 11:10:17
@OliCharlesworth:我不明白。想想如何一個從按鈕派生的切換按鈕,我可以看到基類應該可實例化的情況,這個問題可能出現在現實世界中。因此我不會遵循任何「所有基礎都必須抽象」的方法。如果這不是你想到的,那麼請詳細說明抽象基類如何能夠幫助我解決問題。 – MvG 2014-08-28 11:10:21