2

I'm writing something in C++. I have 2 classes which I want to contain one into the other as in the folowing (these are just the header files):

//Timing.h

#ifndef _Timing_h
#define _Timing_h
#include "Agent.h"

class Timing{
    private:
        typedef struct Message{
            Agent* _agent; //i get here a compilation problem
            double _id;
        } Message;
        typedef struct MessageArr{
        } MessageArr;
    public:
        Timing();
        ~Timing();
};
#endif

//Agent.h

#ifndef _Agent_h
#define _Agent_h
#include <string>
#include "Timing.h"
using namespace std;

class Agent{
    public:
        Agent(string agentName);
        void SetNextAgent(Agent* nextAgent);
        Agent* GetNextAgent();
        void SendMessage(Agent* toAgent, double id);
        void RecieveMessage(double val);
        ~Agent();
    private:
        string _agentName;
        double _pID;
        double _mID;
        Agent* _nextAgent;
};
#endif

The compilation error is in the Timing.h file inside the definition of the struct:

expected ';' before '*' token

What am I doing wrong?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
or.nomore
  • 915
  • 1
  • 10
  • 20

4 Answers4

4

Try not to include "Agent.h" in Timing.h but include a forward reference instead:

#ifndef _Timing_h
#define _Timing_h
class Agent;

class Timing{
    private:
        typedef struct Message{
            Agent* _agent; //I get here a compilation problem
            double _id;
        }Message;

        typedef struct MessageArr{
        }MessageArr;

    public:
        Timing();
        ~Timing();
};
#endif

You can include Agent.h in the timing.cpp file.

This way you remove the circular reference and you reduce the coupling between the classes. Since you don't use the class Timing in your class Agent, you can remove this include as well (but this might be a copy mistake from your shortened example).


Basically - whenever you need either the size of an object or some of it's functionality, you must include its header file. If you don't need it (e.g. if you use only pointers to this object or references), you should not. This reduces compile time (especially for large projects)


For the 1 instance problem - check your favorite design patterns book (e.g. the GoF). The singleton pattern might be what you need.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Tobias Langner
  • 10,634
  • 6
  • 46
  • 76
  • Yeah! it did help, but what if i want to create in the Agent.h file some functions from Timing.h? do i need the include Agent.h in Timing.h? – or.nomore Sep 01 '10 at 12:53
  • 2
    Because when all you are doing is using a class as a return type, a pointer or reference member, or a pointer or reference parameter, the compiler does not need to see a complete definition of the class in order to proceed. A simple forward-declaration saying "there is a class with the following name" is sufficient. If you want to actually *use* objects of a given type, you need a complete delcaration. So within timing.cpp, where the `Message::_agent` field is actually *used*, you do need to have included the entire definition of `Agent` (agent.h). – Tyler McHenry Sep 01 '10 at 13:01
  • if i want to create only one instance of Timing? can i create a static field inside the Agent.h file? how can i do it? – or.nomore Sep 01 '10 at 15:02
  • Short answer is yes, but it might be worthwhile to ask that as a new question with more detail about what you're trying to accomplish. – Tyler McHenry Sep 01 '10 at 15:15
3

Rule of thumb.

  1. Do not include other header files from your header files if you don't need to.
    • Pre-Compiled header file stuff being a notable exception.
  2. If your class only depends on a pointer or a reference you do not need the header file:
    • Use forward declaration in this situation.
  3. In the source file include only the header files you need to make it work
    • Include them from most specific to least specific.
    • This will prevent the problem of hiding a dependency.

Other notes:

  • Do not use Underscore followed by a capitol letter.
    • This is reserved for the implementation. see
    • As in #define _Timing_h
    • Also note it is traditional that macros are all upper case.
  • Do not put using namespace X; in a header file
    • If you do this you pollute the namespace for everybody that uses your header file.
      This is a real easy way to PO other developers who now have to re-factor their code to make sure it does not use any of a bunch of new classes/functions/templates that are suddenly being resolved against that was not there before.

So try this:

Timing.h

#ifndef TIMING_H
#define TIMING_H

class Agent;

class Timing{
// STUFF
};
#endif

Agent.h

#ifndef AGENT_H
#define AGENT_H

#include <string>

class Agent{
// STUFF
}; 
#endif

Timing.cpp

#include "Timing.h"
#include "Agent.h"

// STUFF

Agent.h

#include "Agent.h"
using std::string;   // Bring as little as possable into the the global namespace.
                     // prefer to prefix all cases with std::

// STUFF.
Community
  • 1
  • 1
Martin York
  • 257,169
  • 86
  • 333
  • 562
2

You can't have circular includes.

Stop including "Timing.h" from "Agent.h", since it's not needed there.

Also, you don't need to have the "Agent.h" included in "Timing.h" either, just use a forward reference:

class Agent;

This makes it possible to have pointers to something called Agent.

unwind
  • 391,730
  • 64
  • 469
  • 606
1

You need to add the forward declaration of Agent in Timing.h

// Timing.h
#ifndef _Timing_h
#define _Timing_h   

class Agent; // fwd declaration.

class Timing{
    private:
        typedef struct Message{
            Agent* _agent; // without fwd decln Agent type is unknown here.
// rest all same.

EDIT:

As suggested by others, you should not be including Agent.h in Timing.h

codaddict
  • 445,704
  • 82
  • 492
  • 529