2016-10-02 135 views
1

我正在爲正在開發的C++應用程序編寫一個小的層次結構的異常類,並且我無法間接從std::runtime_error派生。這裏是代碼類似於什麼我至今寫:從沒有默認構造函數的虛擬基礎派生類

class RuntimeException : public virtual boost::exception, public virtual std::runtime_error { 
public: 
    virtual ~RuntimeException() {} 
    RuntimeException() : runtime_error("A RuntimeException occurred.") {} 
    RuntimeException(const std::string& what) : runtime_error(what) {} 
}; 

class IllegalArgumentException : public virtual RuntimeException { 
public: 
    IllegalArgumentException() : RuntimeException("An IllegalArgumentException occurred.") {} 
    IllegalArgumentException(const std::string& what) : RuntimeException(what) {} 
}; 

RuntimeException類編譯沒有問題,但IllegalArgumentException拒絕彙編VS2015,生成錯誤:no default constructor exists for class "std::runtime_error"IllegalArgumentException兩個構造。這促使我C++繼承層次的瞭解,如我所料這段代碼編譯的罰款。

我的理解是,IllegalArgumentException應該編譯,因爲,雖然這是事實,std::runtime_error沒有默認的構造函數,它的構造是由構造爲RuntimeException調用。但顯然這必須是錯誤的,因爲編譯器正在拒絕它。它似乎想我直接從IllegalArgumentException構造函數調用std::runtime_error構造函數(編譯錯誤消失,當我這樣做),但是這似乎是錯誤的,因爲這樣我會被要求std::runtime_error構造器兩次:一次是在構造函數RuntimeException,並再次在IllegalArgumentException的構造函數中。

這是安全和/或有效的嗎?如果不是,編譯器爲什麼似乎鼓勵它呢?我可能只是從std::exception派生並實現std::string我自己作爲成員變量,但我認爲從已經實現了這一點的標準類派生將更容易。這是錯誤的方法嗎?此外,事實上,我從boost:exceptionstd::runtime_error幾乎都會導致這個問題?

回答

2

當使用virtual繼承virtual鹼的構造函數調用是最派生類的責任,而不是任何中間類的責任。原因很明顯:使用virtual繼承表示有一個期望,即實際上存在多個使用基類的派生類。哪一個派生類將負責構建virtual基地?

所以,任何派生類的構造函數需要提供的參數來virtual鹼,例如:

IllegalArgumentException::IllegalArgumentException(std::string const& what) 
    : std::runtime_error(what) 
    , RuntimeException(what) { 
} 

爲了避免中間鹼基調用virtual基類的用於virtual繼承的構造通常提供一個默認的構造函數。當然,這可能會導致大多數派生類錯誤地依賴於被其中一個基礎調用的正確構造函數。

+0

謝謝你,你的解釋很清楚。鑑於此,我很可能最終會從'std :: exception'派生並使用我自己的'std :: string'。這似乎是最簡單的方法。 –

相關問題