2011-12-22 94 views
4

我得到这个界面我已经写了:C++ - 虚拟析构函数和链接错误

#ifndef _I_LOG_H 
#define _I_LOG_H 

class ILog { 
public: 
    ILog(); 
    virtual ~ILog(); 

    virtual void LogInfo(const char* msg, ...) = 0; 
    virtual void LogDebug(const char* msg, ...) = 0; 
    virtual void LogWarn(const char* msg, ...) = 0; 
    virtual void LogError(const char* msg, ...) = 0; 

private: 
    Monkey* monkey; 
}; 

#endif 

的方法都是纯虚函数,因此必须通过派生类实现。 如果我尽量让继承这个界面我得到以下链接错误类:

Undefined reference to ILog::ILog 
Undefined reference to ILog::~ILog 

我明白为什么有一个虚拟的析构函数(以确保派生的析构函数被调用),但我不明白为什么我得到这个链接器错误。

编辑:好的,所以我需要定义虚析构以及。 但是我仍然可以在虚拟析构函数的定义中执行东西,还是只是简单地调用我的派生类析构函数并跳过它? 一样,将这个触发:

virtual ~ILog() { delete monkey; } 
+0

当然,这将触发。 – Truncheon 2011-12-22 21:59:04

+0

可能重复[什么是未定义的引用/未解析的外部符号错误,以及如何解决它?](http://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external- symbol-error-and-how-do-i-fix) – 2015-08-12 06:42:05

回答

10

您还没有定义构造函数和析构函数中,只宣布他们

尝试

class ILog { 
public: 
    //note, I want the compiler-generated default constructor, so I don't write one 
    virtual ~ILog(){} //empty body 

    virtual void LogInfo(const char* msg, ...) = 0; 
    virtual void LogDebug(const char* msg, ...) = 0; 
    virtual void LogWarn(const char* msg, ...) = 0; 
    virtual void LogError(const char* msg, ...) = 0; 
}; 
  • 构造:一旦你声明构造,任何构造函数,编译器都不会为您生成默认构造函数。派生类的构造函数试图调用接口的构造函数,并且没有定义,只是声明。无论是提供一个定义,或删除的声明
  • 析构函数:其他考虑单独留在家中(例如,如上面类似的考虑)的析构函数是虚拟的。每个非纯虚拟函数必须具有定义(因为它是由定义使用)。

我还可以在虚拟的析构函数, 的定义执行的东西还是会简单地叫我的派生类的析构函数并跳过它? 喜欢,请问这个触发器

是的,你可以。当派生类的析构函数被调用时,它会自动调用基类的析构函数。然而,我不能想象,在一个接口的析构函数中执行它是有意义的。但在技术上你可以在析构函数做任何事情,哪怕是虚拟的

+0

我可以在虚拟析构函数定义中做些什么吗?更新了我的问题 – KaiserJohaan 2011-12-22 21:49:51

+0

@KaiserJohaan:当然可以,但是如果***界面***只会声明纯虚函数,你会怎么做?你会做什么可能的清理?它是派生类(接口的实现者)应该清理它们使用的资源(如果有的话)。 – 2011-12-22 21:51:35

+0

@KaiserJohaan:更新我的回答 – 2011-12-22 21:57:45

0

只需提供构造函数和析构函数,编译器的在线版本将不会生成链接器便无法对它们的引用。

ILog() {}; 
virtual ~ILog() {}; 
3

你忘了添加一个空函数虚拟析构函数。函数体实际上并没有做任何事情,C++可能把低级别的破坏代​​码在派生类的析构函数(不能完全确定上),但它仍然需要:

#ifndef _I_LOG_H 
#define _I_LOG_H 

struct ILog { 
    virtual ~ILog(); 
    // virtual ~ILog() = 0; // either works 

    virtual void LogInfo(const char* msg, ...) = 0; 
    virtual void LogDebug(const char* msg, ...) = 0; 
    virtual void LogWarn(const char* msg, ...) = 0; 
    virtual void LogError(const char* msg, ...) = 0; 
}; 

#endif 

CPP文件:

ILog::~ILog() 
{ // this does get called 
} 

更新了例:

#include <iostream> 

struct Monkey 
{ 
    int data; 
}; 

struct ILog 
{ 
    ILog() : monkey(0) {} 
    virtual ~ILog() = 0; 

    virtual void LogInfo(const char* msg, ...) = 0; 
    virtual void LogDebug(const char* msg, ...) = 0; 
    virtual void LogWarn(const char* msg, ...) = 0; 
    virtual void LogError(const char* msg, ...) = 0; 

    void storeMonkey(Monkey* pM) 
    { 
     delete monkey; 
     monkey = pM; 
    } 

    void message() 
    { 
     std::cout << "monkey->data contains " << monkey->data; 
    } 

private: 
    Monkey* monkey; 
}; 

struct ILogD : ILog 
{ 
    int data; 

    ILogD(Monkey* pM) 
    { 
     storeMonkey(pM); 
    } 

    void LogInfo(const char* msg, ...) {}; 
    void LogDebug(const char* msg, ...) {}; 
    void LogWarn(const char* msg, ...) {}; 
    void LogError(const char* msg, ...) {}; 
}; 

ILog::~ILog() 
{ 
    delete monkey; 
} 



int main() 
{ 
    ILogD o(new Monkey()); 

    o.message(); 
} 
+0

“你忘了为纯虚拟析构函数添加一个空函数。”这里的析构函数不是纯粹的虚拟。它不应该是 – 2011-12-22 21:50:11

+0

语法是纯虚拟的,即使它在技术上不是析构函数。 – Truncheon 2011-12-22 21:51:10

+0

我不明白你在说什么对不起。我在说的是,在原始问题中,析构函数只是虚拟的,而不是***纯粹的虚拟 – 2011-12-22 21:52:43