2015-11-04 129 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