Reputation: 670
Consider the following example:
a.h
:
#ifndef A_H
#define A_H
#include <vector>
#include <memory>
#include "b.h"
enum class SActionType;
class A {
std::vector<std::unique_ptr<B>> my_bees;
public:
A();
void print(int x, int y);
};
#endif
a.cc
:
#include <iostream>
#include "a.h"
A::A() {
}
void A::print(int x, int y) {
std::cout << "hi this is not going to work" << std::endl;
}
b.h
:
#ifndef B_H
#define B_H
#include <memory>
#include <vector>
// #include "a.h"
class A;
class B {
std::shared_ptr<A> a;
public:
B(std::shared_ptr<A> a);
void foo();
};
#endif
b.cc
:
#include <algorithm>
#include "b.h"
B::B(std::shared_ptr<A> a):
a{a}
{}
void B::foo() {
a->print(1, 2);
}
main.cc
:
#include "a.h"
#include "b.h"
int main() {
return 0;
}
Makefile
:
exec: main.o a.o b.o
g++ -std=c++14 -o exec
main.o: main.cc
a.o: a.cc a.h
b.o: b.cc b.h
After running make
, I get the following error:
me:~$ make
g++ -c -o b.o b.cc
b.cc: In member function ‘void B::foo()’:
b.cc:9:6: error: invalid use of incomplete type ‘using element_type = class A {aka class A}’
a->print(1, 2);
^~
In file included from b.cc:2:0:
b.h:8:7: note: forward declaration of ‘using element_type = class A {aka class A}’
class A;
^
<builtin>: recipe for target 'b.o' failed
make: *** [b.o] Error 1
Why is this happening? I thought that this would work because of class B
does not actually need to access the member functions of A until the .cc
files, and just having the forward declaration in the header file would be enough to circumvent the circular dependency.
Upvotes: 1
Views: 403
Reputation: 29148
I thought that this would work because of class
B
does not actually need to access the member functions ofA
until the.cc
files
That's correct. b.h
does not need to include a.h
(nor does a.h
need to include b.h
). But b.cc
needs to include both. Nothing circular about that. After all, a.cc
does the same thing.
b.cc
#include <algorithm>
#include "a.h"
#include "b.h"
B::B(std::shared_ptr<A> a):
a{a}
{}
void B::foo() {
a->print(1, 2);
}
Upvotes: 3
Reputation: 310920
The compiler needs to know the complete type of the class A that to check for example that this construction
void B::foo() {
a->print(1, 2);
}
is valid that is that the class A contains the member function (static or non-static?) print
.
Upvotes: 0