2012-06-07 56 views
12

假設我有兩個類,第一個用於寫入原語類型(boolintfloat等)和延伸的第一到也寫複雜類型的第二個:爲什麼C++更喜歡這種模板方法來重載方法?

struct Writer { 
    virtual void Write(int value) = 0; 
}; 

struct ComplexWriter : public Writer { 
    template <typename TValue> void Write(const TValue &value) { 
     boost::any any(value); 
     Write(any); 
    } 
    //virtual void Write(int value) = 0; // see question below 
    virtual void Write(const boost::any &any) = 0; 
}; 

的想法是,如果有人呼叫myWriter.Write(someIntValue);,int重載將優先於模板方法。相反,我的編譯器(Visual C++ 11.0 RC)總是選擇模板方法。下面的代碼片段,例如,將打印Wrote any到控制檯:

struct ComplexWriterImpl : public ComplexWriter { 
    virtual void Write(int value) { std::cout << "Wrote an int"; } 
    virtual void Write(const boost::any &any) { std::cout << "Wrote any"; } 
}; 

void TestWriter(ComplexWriter &writer) { 
    int x = 0; 
    writer.Write(x); 
} 

int main() { 
    ComplexWriterImpl writer; 
    TestWriter(writer); 
} 

行爲突然改變,當我在ComplexWriter類聲明Write(int)方法,以及(見第一個片段註釋掉線)。然後它將Wrote an int打印到控制檯。

這是我的編譯器應該如何表現? C++標準是否明確規定只有在同一個類(而不是基類)中定義的重載應該優先於模板化方法?

+2

我沒有看到你重載的方法了結INT與一個模板。你有兩個不相關的類,'Writer',一個採用'int'和'ComplexWriter'方法的模板方法(以及一個採用'boost :: any const&'的方法)。在你的測試代碼中你使用'ComplexWriter',所以它當然會調用'ComplexWriter'的成員。如果你真的希望它調用完全不相關的類'Writer'的成員,你能解釋爲什麼(以及如何)它應該這樣做嗎? – celtschk

+2

您提到'ComplexWriter'擴展了'Writer',但是在您列出的代碼中不會從'Writer'繼承。這是正確的設置? – Attila

+0

謝謝你指出。是的,ComplexWriter應該來自Writer。我相應地更新了這個問題。結果仍然是一樣的(儘管當然忘記指定基類連接到我的問題核心)。 – Cygon

回答

7

的問題是,在點你調用writer.Write(x)編譯器遇到ComplexWriter不是ComplexWriterImpl,所以它只是注意到ComplexWriter定義的函數 - 模板功能和boost::any功能。

ComplexWriter不包含接受int任何虛函數,所以它沒有辦法通過打電話到ComplexWriterImpl

定義。當你在虛擬超載添加到ComplexWriter類中的int超負荷,那麼編譯器意識到有在ComplexWriter類的整過載,因此通過它呼籲在ComplexWriterImpl

編輯執行:現在你已經在ComplexWriter &作家之間的繼承編輯,我有一個更完整的解釋你:

當你創建一個子類並在其中定義一個函數時,那麼無論它們的參數類型如何,基類中該名稱的所有函數都將被隱藏。

你可以繞過這與使用關鍵字,我相信:

struct ComplexWriter : public Writer { 
    template <typename TValue> void Write(const TValue &value) { 
     boost::any any(value); 
     Write(any); 
    } 
    using Writer::Write; 
    virtual void Write(const boost::any &any) = 0; 
}; 

欲瞭解更多詳情,請參閱此FAQ條目:http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9

編輯2:只是爲了證實這確實解決您的問題: http://ideone.com/LRb5a

+0

是的,我忘了在我的代碼片段中指定基類。 ComplexWriter確實繼承了Writer,但我觀察到的行爲正如我所解釋的,即使正確指定了基類。 – Cygon

+0

@Cygon是啊,注意到了。我只是試圖想出一個解釋/編輯。雖然如果我失敗,我可能會刪除這個答案! – obmarg

+0

感謝您在任何情況下的快速回復!忘記指定基類真的是一個愚蠢的錯誤,因爲它歪曲了整個問題:) – Cygon

2

當您通過ComplexWriter「接口」訪問對象時,編譯器將嘗試使用該類中的定義來解析對Write(int)的函數調用。如果它不能這樣做,它會考慮基類。

在這種情況下,您有兩個候選:Write(any)和模板版本。由於目前沒有明確的Write(int),它將不得不在這兩個選項之間進行選擇。Write(any)需要隱式轉換,而模板版本則不需要,因此調用了模板版本(它又調用Write(any))。

爲了使Write(int)Writer可用,導入Writer::Write功能:

class ComplexWriter : public Writer 
{ 
    using Writer::Write; 
    // rest is as before 
}; 
相關問題