Вопрос

Two of my classes had to include each other. I made forward declarations instead, compilation is ok. One function of these classes is to call the destructor of the other. And that the compiler spits warnings at me, the destructor will not be called. What can I do? I can avoid this problem by creating another class for the function I need, avoiding the forward declarations but that would not be educative for me...

Here is my first class 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 is the 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();

}

And here is the other Character.h class:

#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

And here is my Character destructor:

Character::~Character() {

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

}

So when my program ends, I call upon the Header's function "cleanUp()" giving it a vector of pointers to Characters. Every pointer should then be deleted through the Character's destructor ~Character(); However compilation gives me three warnings:

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

And once my program terminates, the character's destructor's message won't show up which means the destructor clearly isn't called.

What am I doing wrong with the forward declarations?

Это было полезно?

Решение

Yep, that's what the (draft) standard says (§5.3.5.5);

If the object being deleted has incomplete class type at the point of deletion and the complete class has a non-trivial destructor or a deallocation function, the behavior is undefined.

(a non trivial destructor being one you defined yourself)

To fix it, just #include "Character.h" in header.cpp before invoking delete to allow the type to be completely declared.

Другие советы

When you use class MyClass; to forward declare your class, this only declares that the thing with the name MyClass is a class, it does not declare the internal methods of the class.

Whenever you need to use one of the internal methods (such as a non-trivial destructor) you need to include the full declaration of the class (this means include the header file containing the class definition). Without this, the compiler has no way of knowing what the internal structure of your class actually looks like.

Here is an example:

// 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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top