3

我的两个课程必须相互包含。我做了前向声明,编译没问题。这些类的一个功能是调用另一个类的析构函数。并且编译器向我吐出警告,析构函数将不会被调用。我能做些什么?我可以通过为我需要的函数创建另一个类来避免这个问题,避免前向声明,但这对我没有教育意义......

这是我的第一堂课 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::~Character() {

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

}

因此,当我的程序结束时,我调用 Header 的函数“cleanUp()”给它一个指向字符的指针向量。然后应该通过 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

一旦我的程序终止,角色的析构函数消息就不会出现,这意味着析构函数显然没有被调用。

我对前向声明做错了什么?

4

2 回答 2

3

是的,这就是(草案)标准所说的(§5.3.5.5);

如果要删除的对象在删除点具有不完整的类类型,并且完整的类具有非平凡的析构函数或释放函数,则行为未定义。

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

要修复它,就#include "Character.h"header.cpp调用之前delete允许完全声明类型。

于 2013-08-31T16:49:02.283 回答
0

当您使用class MyClass;前向声明您的类时,它只声明名称MyClass为 a的事物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;
}
于 2013-08-31T17:17:30.420 回答