2015-11-04 163 views
-1

我在實現一個在另外兩個類中的抽象類中聲明的虛函數時遇到了問題,在不同的頭文件中。虛擬函數C++:虛擬函數已經有一個主體

當我在類ProtocolLogin中實現ProtocolGame中已經實現的虛函數「parsePacket」時,編譯器返回「函數已經有一個body」。

Error 1 error LNK2005: "private: virtual void __cdecl ProtocolGame::parsePacket(class NetworkMessage &)" ([email protected]@@[email protected]@@Z) already defined in protocolgame.obj 

Error 2 error LNK2001: unresolved external symbol "public: virtual void __cdecl ProtocolLogin::parsePacket(class NetworkMessage &)" ([email protected]@@[email protected]@@Z) 

然後我試圖創建一個名爲parseWater一個新的虛擬功能,將只在類ProtocolLogin實施,編譯器返回我「功能,需要在ProtocolGame被聲明」,但如果我這樣做,我得到再次:「功能已經有一個身體」。所以,我只是不再遵循。請幫我理解:)

它就像一個無盡的循環。

class Protocol (Header File 1) 
{ 
    public: 
     explicit Protocol(Connection_ptr connection) : m_connection(connection) 
     virtual ~Protocol() = default; 

     // non-copyable 
     Protocol(const Protocol&) = delete; 
     Protocol& operator=(const Protocol&) = delete; 

     virtual void parsePacket(NetworkMessage&) {} 
     void onRecvMessage(NetworkMessage& msg); // Function that calls parsePacket 
     virtual void onRecvFirstMessage(NetworkMessage& msg) = 0; 

class ProtocolGame final : public Protocol (Header File 2) 
{ 
    public: 
     // static protocol information 
     enum {server_sends_first = true}; 
     enum {protocol_identifier = 0}; // Not required as we send first 
     enum {use_checksum = true}; 
     static const char* protocol_name() { 
      return "gameworld protocol"; 
     } 

     explicit ProtocolGame(Connection_ptr connection); 

      private: 
     void parsePacket(NetworkMessage& msg) final; //implementation //Works 
     void onRecvFirstMessage(NetworkMessage& msg) final; //implementation //Works 

    class ProtocolLogin final : public Protocol (Header File 3) 
{ 
    public: 
     // static protocol information 
     enum {server_sends_first = false}; 
     enum {protocol_identifier = 0x01}; 
     enum {use_checksum = true}; 
     static const char* protocol_name() { 
      return "login protocol"; 
     } 

     explicit ProtocolLogin(Connection_ptr connection) : Protocol(connection) {} 

     void onRecvFirstMessage(NetworkMessage& msg); //work 
     void parsePacket(NetworkMessage& msg); // dont work 
+0

不清楚的碼是真正的碼,什麼是真正的錯誤。請按原樣提供代碼,並按錯誤報告的行填入錯誤。在附註中,您最終使用代碼的目的是什麼?我相信這是一個不好的做法。 – SergeyA

+0

首先,'void onRecvLiquid();'不是虛擬 – StoryTeller

+0

[MCVE](http://stackoverflow.com/help/mcve)。 –

回答

0

parseWater是唯一聲明爲final的最終函數。

所有其他final功能沒有virtual關鍵字的某處。

正如StoryTeller指出的那樣「您不必在派生分類中重新聲明虛擬說明符。」

+0

我編輯並更改了我在這裏引用時拼錯的功能。抱歉。它現在正確。請閱讀它:) – Xabirau

+0

你爲什麼拒絕我的編輯?你的代碼仍然不可編譯,難以閱讀... –

+0

修復了明顯的錯誤(分號,括號等)後,新版本適用於我(MSVC2015) - 查看我的代碼編輯 –

0

我並不十分熟悉C++ 11,但要實現的虛函數的派生類也需要聲明它們的實現爲virtual。我不認爲final消除了需要註明virtual。 (物質事實,這是一個錯誤申報非虛擬函數作爲final

如果你發現,你的父類已經parseWater()定義和virtual,但不parseAlchohol(),這就是爲什麼你ProtocolAlchohol類沒有按」噸有聲明void parseAlchohol() final;一個問題,ProtocolWater有問題與void parseWater() final;

ps的,我不知道你要推導和OOP的權利,如果你明確提到子類的概念(即水& alchohol)在父類和基於w的命名函數ater & alchohol。

編輯:沒關係我的第一段。我想我總是把它作爲一種慣例,並沒有意識到這是沒有必要的。

+2

你不*有*重新派生類中的虛擬說明符。 – StoryTeller

+1

「你想要實現虛函數的派生類也需要聲明它們的實現是虛擬的。」不正確。 –

+0

最終說明符_「指定在派生類中不能覆蓋虛擬函數,或者不能從類繼承類。」這可能有助於在基類中聲明公用函數,但可以防止它們在派生類中超載。 (http://en.cppreference.com/w/cpp/language/final) –

0

由於我們正在討論在派生類中使用virtual,我想發表一個聲明。不幸的是,在我看來,C++在這方面不一致。你可能會也可能不會'虛擬'重述。更糟糕的是,當它在基類中不是虛擬的時候,你可以創建一個虛擬函數 - 這可能會讓代碼閱讀器顯示函數是虛擬的 - 這是一個錯誤的指示。

如果C++實際上強制使用虛擬 - 在虛擬函數的所有重新定義中都要求它,並且禁止它在非虛擬的重新定義上,那麼對代碼維護者來說,它會容易得多。

+0

我在此處引用它時編輯並更改了我拼錯的功能。抱歉。它現在正確。請閱讀它:) – Xabirau

+0

對於語言流利的程序員來說,這些都不是問題。 – StoryTeller

+0

@StoryTeller,真的嗎?非問題? 'struct X {}; struct foo:Base {void f(); }; f()是虛擬的嗎? – SergeyA