-2

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.

  • 3
    Are you by change doing a `using namespace std;` in some place and not another? Quit using that anyplace and qualify your strings as: `std::string` and see if that fixes it. – lakeweb Feb 10 '19 at 00:48
  • My guess would be, you have circular includes. Hard to be sure without a [mcve] – Igor Tandetnik Feb 10 '19 at 01:40
  • My guess is that `Parameter.h` only works if preceded by `#include ` and `using namespace std` (or possibly `using std::string`). Header files need to be self contained, and (in most circumstances) also avoid `using` in such contexts. In other words, `#include ` in `Parameter.h`, don't use `using namespace std` in it, and use `std::string` to refer to `string` in all headers. However, that's a guess, since you haven't provided a [mcve] and haven't bothered to describe what diagnostics your compiler is producing. – Peter Feb 10 '19 at 02:33

1 Answers1

0

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.

Richard
  • 338
  • 2
  • 11