2011-12-22 99 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