Julián Lomba Castro Julián Lomba Castro - 1 month ago 14
C++ Question

"invalid use of incomplete type". Solving circular dependencies

I'm a newbie in C++ and I have been trying different suggestions from other questions but I can't make my code work.

I have a class "PChar" and another class "Action". An Action has two PChar members and a method of PChar ("act()") has to be able to create an Action object. So after trying different things I got this code:

"action.h":

#ifndef ACTION_H
#define ACTION_H

class PChar;

class Action
{
PChar *subject, *object;
public:
Action();
Action(PChar& p1, PChar& p2);
};


#endif


"action.cpp":

#include "action.h"

Action::Action(){};

Action::Action(PChar& p1,PChar& p2)
{
*subject=p1;
*object=p2;
};


"character.h"

#ifndef CHARACTER_H
#define CHARACTER_H

#include <string>

#include "action.h"

class PChar
{
public:
std::string name;

PChar();

PChar(std::string input_name);

void act(PChar& target, Action &action);
};
#endif


"character.cpp"

#include "character.h"

PChar::PChar(){}

PChar::PChar(std::string input_name)
{
name=input_name;
}

void PChar::act(PChar& target, Action& action)
{
action=Action(*this, target);
}


"main.cpp"

#include "action.h"
#include "character.h"

int main()
{
PChar char1("Joe");
PChar char2("Matt");
Action handshake;
char1.act(char2, handshake);
}


The goal is to create an object "handshake" which has both characters as members. When compiling I get the error:

action.cpp:7:10: error: invalid use of incomplete type ‘class PChar’
*subject=p1;
^
In file included from action.cpp:1:0:
action.h:4:7: note: forward declaration of ‘class PChar’
class PChar;
^
action.cpp:8:9: error: invalid use of incomplete type ‘class PChar’
*object=p2;
^
In file included from action.cpp:1:0:
action.h:4:7: note: forward declaration of ‘class PChar’
class PChar;
^


This is part of a larger project, that's why the files are structured like that, I just simplified the code to reproduce the error. I have tried solutions from other similar questions but they don't seem to work. Any help or tip is welcome. Thank you!

Answer Source

You can forward declare type to declare pointer or reference to it. But when you start to use that type (declare it as a value or assign to it or call a method) it must be defined. Including character.h in action.cpp would solve compilation error. Note you have UB in your ctor:

Action::Action(PChar& p1,PChar& p2)
{
    *subject=p1;
    *object=p2;
}

as you dereference uninitialized pointers. You need to make them point somewhere, probably you meant to allocate dynamic memory. In that case std::unique_ptr would be preferrable as would solve issues with Rule of 3/5/0:

class Action
{
    std::unique_ptr<PChar> subject, object;
public:
    ...
};

Action::Action(const PChar& p1, const PChar& p2) :
    subject( new PChar(p1) ), object( new PChar(p2) )
{
}

and when you do not have intention to modify object you better pass it as const reference.