4

I have 2 classes A and B and the 4 following files:

A.h

#ifndef A_H
#define A_H

#include "B.h"
class A {
public:
    A();
    int functionA();
    B objectB;
};

#endif //A_H

B.h

#ifndef B_H
#define B_H

class A;
class B {
public:
    B();
    int functionB();
    A * objectA;
};

#endif //B_H

A.cpp

#include "A.h"
A::A(){}
int A::functionA() {
    return 11;
}

B.cpp

#include "B.h"
B::B(){}
int B::functionB() {
    return objectA->functionA();
}

Now I compile using the line: g++ A.cpp B.cpp -Wall -Wextra -O2 -march=native -std=gnu++1z

I get this error:

B.cpp: In member function 'int B::functionB()':
B.cpp:4:19: error: invalid use of incomplete type 'class A'
     return objectA->functionA();
                   ^
In file included from B.cpp:1:0:
B.h:1:7: note: forward declaration of 'class A'
 class A;
       ^

How can I use a member class of the function forward declared here?

oldabl
  • 376
  • 2
  • 12
  • 5
    In the cpp files include both header files. – NathanOliver Oct 04 '17 at 15:39
  • Thanks. Though it does not solve the error, it creates a new one: "error: previous definition of 'class B'" This happens when in B.cpp I add the line #include "A.h" at the top – oldabl Oct 04 '17 at 15:41
  • 5
    Get rid of `#include "B.h"` in `a.h` as it is not needed. You should also be using include guards. – NathanOliver Oct 04 '17 at 15:42
  • This example comes from a more advanced example for my work. I include B.h because I want to highlight the fact that I have to use a forward class in class B – oldabl Oct 04 '17 at 15:44
  • 1
    @oldabl: I'm not sure I follow your logic on how including B.h highlights the forward declaration in B.h. At any rate, though, as Nathan already mentioned, use include guards - e.g., in `A.h` have `#ifndef A_H_` `#define A_H_` at the top of the file and `#endif` at the bottom of the file, and similarly for B.h (but replace `A_H_` with `B_H_`). This ensures that your headers are only included once. – R_Kapp Oct 04 '17 at 15:46
  • @oldabl I'd use a comment for that. Here is an example expressing a circular relationship: https://stackoverflow.com/questions/625799/resolve-build-errors-due-to-circular-dependency-amongst-classes – NathanOliver Oct 04 '17 at 15:47
  • If I was not including it I could just use an include from A.h in B.h. I've just edited the exmaple to relate more to how my example goes. Anyway, I'll use include guards thanks. I'll edit my example to use them – oldabl Oct 04 '17 at 15:49
  • I have already looked at this example yes. And this is what I essentially do! What I don't understand is how I can use a function from class A on objectA in a function of B. – oldabl Oct 04 '17 at 15:53
  • OK so using include guards and including A.h from B.cpp solved my problem. Thank you all! – oldabl Oct 04 '17 at 16:00

3 Answers3

3

Look at what is included when compiling B.cpp, you have a forward declaration of class A but not the real definition. So in B.cpp on line 4, functionA is unknown to the compiler therefore your type is incomplete.

You should include A.h in B.cpp.

jeerbl
  • 7,537
  • 5
  • 25
  • 39
Antho A
  • 78
  • 8
2

In A.cpp , Include both A.h and B.h
In B.cpp, Include both B.h and A.h.

It works because:

  1. We don't have cyclic inclusion (a header file which includes another header file, which includes the original)
  2. Each class implementation "sees" how the other class looks like, but not how it's implemented, we don't break "separation of interface from implementation" rule. there are some cases where we don't do that, but for most cases, it's valid.

The thumb rule (only a thumb rule!) is to include the class header in every .cpp file which uses that class. so if foo.cpp uses the class bar, and class bar interface is in bar.h, then foo.cpp should include bar.h. There are some specific cases we don't follow that rule, but for the most cases, it's valid.

David Haim
  • 25,446
  • 3
  • 44
  • 78
1

Using members of a class with only a forward declaration is impossible.

If your code uses a member function, the class should be fully declared, because the compiler needs to check that the member function with this name actually exists.

anatolyg
  • 26,506
  • 9
  • 60
  • 134