2013-08-31 46 views
2

我的两个类必须包含对方。我做了前面的声明,编译没问题。这些类的一个功能是调用另一个类的析构函数。而且编译器向我吐出警告,析构函数将不会被调用。我能做什么?我可以通过创建另一个类,因为我需要的功能,避免了向前声明避免这个问题,不过这不会是教育性我...C++前向声明和析构函数

这是我的第一类Header.h:

#ifndef H_HEADER 
#define H_HEADER 

#include "SDL/SDL.h" 
#include "SDL/SDL_image.h" 
#include "SDL/SDL_ttf.h" 
#include <string> 
#include <iostream> 
#include <fstream> 
#include <vector> 
#include <sstream> 
#include "DataFiles.h" 

class Character; // forward declaration Header <-> Character 

class Header { 

private: 
Character * ch; 
}; 

void cleanUp(std::vector <SDL_Surface*> & Vsurface, std::vector <TTF_Font*> & Vfont, std::vector <Character*> & Vchar); 

// ... Other functions use in main.cpp 

#endif 

这里是Header.cpp:

#include "Header.h" 
using namespace std; 


void cleanUp(vector <SDL_Surface*> & Vsurface, vector <TTF_Font*> & Vfont, vector <Character*> & Vchar) { 

for(unsigned int i(0); i < Vsurface.size(); i++) 
    SDL_FreeSurface(Vsurface[i]); 
for(unsigned int i(0); i < Vfont.size(); i++) 
    TTF_CloseFont(Vfont[i]); 
for(unsigned int i(0); i < Vchar.size(); i++) 
    delete Vchar[i]; 

TTF_Quit(); 
SDL_Quit(); 

} 

这里是其他Character.h类:

#ifndef H_CHARACTER 
#define H_CHARACTER 

#include <string> 
#include <iostream> 
#include <sstream> 
#include <vector> 
#include </usr/include/SDL/SDL_image.h> 
#include </usr/include/SDL/SDL.h> 
#include </usr/include/SDL/SDL_ttf.h> 

#include "DataFiles.h" 
#include "CharFrame.h" 

class Header; // Forward declaration Header <-> Character 

class Character { 

public: 
Character(std::string& dataPath); 
~Character(); 
// .. other functions 

private: 

Header * h; 
// ... other attributes 
}; 
#endif 

这里是我的性格的析构函数:

Character::~Character() { 

cout << "Character " << m_name << " deleted.\n-----------------------------------\n" << endl; 

} 

所以我的节目结束的时候,我呼吁头的功能“清理()”给它的指针到字符的载体。然后应该通过角色的析构函数删除每个指针〜Character(); 然而编译给了我三次警告:

Header.cpp: In function ‘void cleanUp(std::vector<SDL_Surface*>&, std::vector<_TTF_Font*>&, std::vector<Character*>&)’: 
Header.cpp:66:17: warning: possible problem detected in invocation of delete operator: [enabled by default] 
Header.cpp:66:17: warning: invalid use of incomplete type ‘struct Character’ [enabled by default] 
Header.h:27:7: warning: forward declaration of ‘struct Character’ [enabled by default] 
Header.cpp:66:17: note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined 

而且一旦我的程序终止时,人物的析构函数的消息将不会出现,这意味着析构函数显然不叫。

我在做什么毛病向前声明?

+2

您是否在'Header.cpp'中包含了'Character.h'?如果没有,请尝试一下。 – ilent2

+0

没有这会反对声明如何工作。看到cmaster的答案在那里:http://stackoverflow.com/questions/18549134/c-headers-inclusions;) –

+1

cmaster的答案是谈论包括'Header.h'内的'Character.h'(以及为什么你不应该做这个)。但是你最终需要包含'Character.h',以便编译器知道在哪里找到它。 'Header.cpp'里面适当的地方。 – ilent2

回答

1

没错,这就是(草案)标准说什么(§5.3.5.5);

如果对象被删除在删除的点具有不完整的类型和完整的类具有 非平凡的析构函数或解除分配功能,行为理解过程音响定义。

(非平凡的析构函数是一个你自己定义的)

要调用delete允许类型完全申报之前将其修复,在header.cpp只是#include "Character.h"

+0

是的,工作正常!我认为,我的析构函数并不重要。但是我怎么知道要删除的对象是否有不完整的类类型呢? –

+0

@AlexandreToqué基本上,您必须相信编译器才能告诉您('警告:对使用不完整类型'结构字符'(默认启用)'进行了无效使用',遗憾的是相当容易忘记包含头文件并最终结束类型不完整。 –

0

当您使用class MyClass;转发声明您的类时,它只声明名称MyClassclass,它不声明该类的内部方法。当需要使用内部方法之一(例如非平凡的析构函数)时,需要包含类的完整声明(这意味着包含包含类定义的头文件)。没有这个,编译器无法知道你的类的内部结构是什么样子的。

下面是一个例子:

// main.cpp 
#include "head1.hpp"  // An instance of Head1 is created in this file 
#include "head2.hpp"  // An instance of Head2 is created in this file 

int main(int argc, char** argv) 
{ 
    Head1 head1(true); 
    Head2 head2(true); 
    return 0; 
} 

// head1.hpp 
#ifndef HEAD1_HPP 
#define HEAD1_HPP 

class Head2;  // A pointer to a class is declared, but no instance is created 
        // so here we only need a forward declaration 

class Head1 
{ 
public: 
    Head1(bool real=false); 
    ~Head1(); 

private: 
    Head2* myHead2; 
}; 

#endif /* #ifndef HEAD1_HPP */ 

// head2.hpp 
#ifndef HEAD2_HPP 
#define HEAD2_HPP 

class Head1;      // Same as above 

class Head2 
{ 
public: 
    Head2(bool real=false); 
    ~Head2(); 

private: 
    Head1* myHead1; 
}; 

#endif /* #ifndef HEAD2_HPP */ 

// head1.cpp 
#include "head1.hpp"    // Include the header we are defining methods for 
#include "head2.hpp"    // We also create an instance of Head2 in here 
#include <iostream> 
using namespace std; 

Head1::Head1(bool real) { 
    myHead2 = real ? new Head2() : NULL; 
    cout << "Hello Head 1" << endl; 
} 

Head1::~Head1() { 
    cout << "Bye Head 1" << endl; 
    if (myHead2 != NULL) delete myHead2; 
} 

// head2.cpp 
#include "head2.hpp"      // As above 
#include "head1.hpp" 
#include <iostream> 
using namespace std; 

Head2::Head2(bool real) { 
    myHead1 = real ? new Head1() : NULL; 
    cout << "Hello Head 2" << endl; 
} 

Head2::~Head2() { 
    cout << "Bye Head 2" << endl; 
    if (myHead1 != NULL) delete myHead1; 
}