【问题标题】:C++ Forward declaration and destructorC++ 前向声明和析构函数
【发布时间】:2013-08-31 16:32:46
【问题描述】:

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

这是我的第一堂课 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() 删除每个指针; 但是编译给了我三个警告:

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

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

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

【问题讨论】:

  • 您是否将Character.h 包含在Header.cpp 中?如果没有,请尝试一下。
  • 不,这会违反前向声明的工作方式。在那里查看 cmaster 的答案:stackoverflow.com/questions/18549134/c-headers-inclusions ;)
  • cmaster 的回答是在 Header.h 中包含 Character.h(以及为什么不应该这样做)。但是您最终需要包含Character.h,以便编译器知道在哪里可以找到它。合适的地方在Header.cpp里面。
  • 等等,对不起,我读的是 Header.h 而不是 .cpp。它现在工作得很好:) 但是我不明白,为什么它会工作?

标签: c++ destructor forward-declaration


【解决方案1】:

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

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

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

要修复它,只需在调用 delete 之前将 #include "Character.h" 放入 header.cpp 以允许完全声明类型。

【讨论】:

  • 是的,工作正常!我认为我的析构函数很重要。但是如何判断要删除的对象的类类型是否不完整呢?
  • @AlexandreToqué 基本上,你必须相信编译器会告诉你(warning: invalid use of incomplete type ‘struct Character’ [enabled by default],很遗憾很容易忘记包含头文件并最终得到一个不完整的类型。
【解决方案2】:

当你使用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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多