For some reason, my compiler won't allow me to use objects of another class as members of another class. Here is my code:
in Parameter.h:
class Parameter {
private:
string type;
string name;
public:
Parameter() {};
string toString();
friend class Predicate;
};
Then, in Predicate.h:
#include "Parameter.h"
class Predicate {
private:
Parameter lParam;
Parameter rParam;
string type;
public:
Predicate() {};
string toString();
friend class Parameter;
};
When I try to compile, I get errors saying that Parameter in Predicate.h does not name a type, and that it was not declared in that scope. I've tried putting the members in both private and public, as well as declaring the friend class in both private and public. I have also tried using pointers to the objects. What am I doing wrong? Thanks.
While you have not yet provided an MVCE, based off of the error you described:
error: ‘Parameter’ does not name a type
you seem to be experiencing a 'circular include' between Parameter.h
and Predicate.h
, as suggested in the comments.
This happens when you declare two classes that both know about the other (Parameter
and Predicate
). Consider Predicate
. At the time of Predicate
's declaration, the compiler needs to already know about Parameter
's existence, since it appears as a member in Predicate
.
The first attempt at a solution would be to include Parameter.h
, which provides Parameter
's declaration. But, Parameter
requires that Predicate
is already declared to make it a friend class
. This is a circular dependency.
The recommended method of resolving this is to use what is called a forward declaration.
// Parameter.h
#pragma once
#include <string>
class Predicate; // Forward declare Predicate
class Parameter {
private:
std::string type;
std::string name;
public:
Parameter() {};
std::string toString() { return "Parameter"; };
friend class Predicate;
};
So this allows us to complete the declaration of Parameter
without needing to include the entire Predicate.h
file. On the other hand, Predicate.h
can continue to include Parameter.h
without issue, since the circular dependency has been broken.
Note that if you call any of Predicate
's methods from Parameter
in the header, forward declarations will not work. That is because the full class declaration is needed in order to call any methods. You can get around this by implementing Parameter
's methods in the source file.
See this similar question for a more general discussion.