我的两个班级必须互相包括在内。我做了前进声明,编译没问题。这些类的一个功能是调用另一个的析构函数。并且编译器向我发出警告,不会调用析构函数。我能做什么?我可以通过为我需要的函数创建另一个类来避免这个问题,避免使用前向声明,但这对我来说不具有教育意义......
这是我的第一堂课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
HEre是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;
}
所以当我的程序结束时,我调用了Header的函数“cleanUp()”,给它一个指向Characters的指针。然后应该通过Character的析构函数~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
一旦我的程序终止,角色的析构函数的消息就不会出现,这意味着析构函数显然不会被调用。
前进声明我做错了什么?
答案 0 :(得分:2)
是的,这就是(草案)标准所说的(§5.3.5.5);
如果要删除的对象在删除时具有不完整的类类型,并且完整的类具有 非平凡的析构函数或释放函数,行为是未定义的。
(一个你自己定义的非平凡的析构函数)
要修复它,只需在#include "Character.h"
中header.cpp
,然后再调用delete
以允许完全声明该类型。
答案 1 :(得分:0)
当您使用class MyClass;
转发声明您的类时,这仅声明名称为MyClass
的事物是class
,它不会声明该类的内部方法。
每当您需要使用其中一个内部方法(例如非平凡的析构函数)时,您需要包含该类的完整声明(这意味着包含包含类定义的头文件)。如果没有这个,编译器无法知道类的内部结构实际上是什么样的。
以下是一个例子:
// 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;
}