2010-04-12 74 views
1

全部。我對C++相當陌生,並且正在用C++編寫一個小型庫(主要用於我自己的項目)。在設計類型層次結構的過程中,我遇到了定義賦值運算符的問題。編譯時的C++類型檢查

我所採取的最終在this article達到的基本方法,這是一個爲每個類MyClass在層次結構從類派生Base定義就像兩個賦值運算符這樣:

class MyClass: public Base { 
public: 
    MyClass& operator =(MyClass const& rhs); 
    virtual MyClass& operator =(Base const& rhs); 
}; 

// automatically gets defined, so we make it call the virtual function below 
MyClass& MyClass::operator =(MyClass const& rhs); 
{ 
    return (*this = static_cast<Base const&>(rhs)); 
} 

MyClass& MyClass::operator =(Base const& rhs); 
{ 
    assert(typeid(rhs) == typeid(*this)); // assigning to different types is a logical error 
    MyClass const& casted_rhs = dynamic_cast<MyClass const&>(rhs); 
    try { 
     // allocate new variables 
     Base::operator =(rhs); 
    } catch(...) { 
     // delete the allocated variables 
     throw; 
    } 
    // assign to member variables 
} 

的一部分我關心的是類型平等的斷言。由於我正在寫一個圖書館,斷言大概會被編出來的最終結果,這導致我去同一個方案,它看起來更像是這樣的:

class MyClass: public Base { 
public: 
    operator =(MyClass const& rhs); // etc 
    virtual inline MyClass& operator =(Base const& rhs) 
    { 
     assert(typeid(rhs) == typeid(*this)); 
     return this->set(static_cast<Base const&>(rhs)); 
    } 
private: 
    MyClass& set(Base const& rhs); // same basic thing 
}; 

但我一直在想,如果我可以在編譯時檢查類型。我看着Boost.TypeTraits,並且通過做BOOST_MPL_ASSERT((boost::is_same<BOOST_TYPEOF(*this), BOOST_TYPEOF(rhs)>));來接近,但是由於rhs被聲明爲對父類而不是派生類的引用,所以它被阻塞了。

現在我想到了,我的推理看起來很愚蠢 - 我希望既然函數是內聯的,它可以自己檢查實際參數,但是當然預處理器總是在編譯器之前運行。但是我想知道是否有人知道我可以在編譯時執行這種檢查。

+1

沒有辦法在編譯時檢查類型,因爲這是多態性的要點:事物的類型只在運行時確定。 '動物*動物=蘭特()%2?新的狗():新的貓();' – UncleBens 2010-04-12 07:02:42

+2

好文章鏈接的方式,謝謝:) – 2010-04-12 09:14:38

回答

7

你不能在編譯時執行這個斷言,原因很簡單,因爲運行時類型直到運行時纔會知道。

assert(typeid(rhs) == typeid(*this)); 
return this->set(static_cast<Base const&>(rhs)); 

在非內聯版本中,您有dynamic_cast。我會保留這一點,以便在違反斷言的情況下獲得定義明確的錯誤而不是未定義的行爲。

如果你這樣做,斷言要麼過於嚴格,要麼毫無意義。 dynamic_cast將在調試版本和發佈版本中引發bad_cast異常。這是你想要的。個人而言,我會質疑整個多態分配問題。我會遵循Scott Meyers的Effective C++建議,並在繼承層次結構摘要中創建所有非葉節點。然後,您可以使基類賦值運算符受保護並且不是虛擬的。

這使您可以在派生類的賦值運算符中使用它們的實現,但會阻止客戶端切片對象。如果一個客戶端類只有一個基類引用或指針,那麼是否應該嘗試分配給該類仍然值得懷疑。如果這樣做,他們應該負責鑄造和類型安全保證。

+3

+ 1爲'保護的'賦值運算符和非葉類的複製構造函數。無論如何總是有複製的虛擬克隆方法。 – 2010-04-12 09:11:45

0

如果你想在編譯時確定事物,那麼動態多態(虛擬函數等)不適合你。我一般認爲沒有必要將動態多態與「普通值類型」混合在一起 - 比如賦值運算符。也許具體的和非多態的類是最適合你的情況。但很難說,因爲你沒有談論你想要做的事情。