3

私のクラスの 2 つは、お互いを含める必要がありました。代わりに前方宣言を行いました。コンパイルは問題ありません。これらのクラスの 1 つの機能は、他のクラスのデストラクタを呼び出すことです。そして、コンパイラが私に警告を吐き出すと、デストラクタは呼び出されません。私に何ができる?必要な関数の別のクラスを作成し、前方宣言を回避することでこの問題を回避できますが、それは私にとって教育的ではありません...

ここに私の最初のクラス 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();

}

もう 1 つの 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;

}

したがって、プログラムが終了すると、ヘッダーの関数「cleanUp()」を呼び出して、文字へのポインターのベクトルを渡します。次に、キャラクターのデストラクタ ~Character(); を介してすべてのポインタを削除する必要があります。ただし、コンパイルで 3 つの警告が表示されます。

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.cppdelete

于 2013-08-31T16:49:02.283 に答える
0

を使用class MyClass;してクラスを前方宣言する場合、これは名前MyClassが aclassであることのみを宣言し、クラスの内部メソッドは宣言しません。

内部メソッドの 1 つ (重要なデストラクタなど) を使用する必要がある場合は常に、クラスの完全な宣言を含める必要があります (これは、クラス定義を含むヘッダー ファイルを含めることを意味します)。これがないと、コンパイラはクラスの内部構造が実際にどのように見えるかを知る方法がありません。

次に例を示します。

// 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 に答える