c++ header inclusion order with conditional compilation - c++

Say I have two files A.hpp and B.hpp
A.hpp:
#indef DEF_A
#define DEF_A
class A{
/*implementation of class A*/
/*some part of it needs B*/
#ifdef DEF_B
void method(B b){/*do something with B*/}
#endif
}
#endif
B.hpp:
#indef DEF_B
#define DEF_B
class B{
/*implementation of class B*/
/*some part of it needs A*/
#ifdef DEF_A
void method(A a){/*do something with A*/}
#endif
}
#endif
I don't want to inclue A.hpp in B.hpp (or vice-versa) because then every time I need A.hpp I will need B.hpp (or vice-versa).
But when in the main file I write :
main.cpp
#include"A.hpp"
#include"B.hpp"
int main(){
A a;
B b;
}
A::method(B b) is unknown. If I reverse the inclusion order I will only have B::method(A a).
Is there a way to have access to both methods when the two headers are included ?
[edit]
The method should also work for template class with no .cpp file.
[/edit]

I would use forward declaration, something like:
A.hpp
#indef DEF_A
#define DEF_A
class B; // Forward declaration of B
class A { // Definition of A
public:
void method(const B& b);
};
#endif
A.cpp
#include "A.hpp"
#include "B.hpp"
void A::method(const B& b) { /* your implementation */ }
B.hpp
#indef DEF_B
#define DEF_B
class A; // Forward declaration of A
class B { // Definition of B
public:
void method(const A& a);
};
#endif
B.cpp
#include "B.hpp"
#include "A.hpp"
void B::method(const A& a) { /* your implementation */ }
And then in main.cpp
you include both A.hpp and B.hpp as you use both of them.
But if in C.cpp you use only A (without B) you can do
C.cpp
#include "A.hpp"
void foo()
{
A a;
// B b; // If uncommented, that would fail to compile.
}

maybe you should give the pimpl-idiom a try. You could easily hide the implementation details in .cpp file, even if its about a templated classes:
//Important: fwd declaration as Jarod42 already stated!
class B;
class AImpl;
class A
{
void aMethod( B* b )
{
impl->( b );
}
AImpl* impl; //this will work because compiler need not to know
//exact object size as we are creating a pointer or
//reference...type definition in cpp
}
// same here for B;
//in cpp file of A and B:
class AImpl : public TemplateClass<X>
{
void aMethod( B* b ){}
};
I hope this will help you with your problem!

Related

C++ circular dependency between multiple classes

I have the following 3 classes: A, B and C. I got errors for circular dependency for random_int(), how can I resolve the following circular dependency?
3x Error: function random_int() is already defined in main.cpp.
Files: C.cpp, A.cpp and B.cpp
A.hpp
#include "B.hpp"
int random_int() {
class C
class A {
public:
void set_b(B& be) {b = be}
B* get_b() {return b;}
static A& getInstance()
{
static A instance;
return instance;
}
private:
B* b;
test();
}
A.cpp
#include "A.hpp"
#include "C.hpp"
void test() {
if (dynamic_cast<C*>(obj)) {
//do stuff
}
}
B.hpp
class C;
class B {
public:
std::vector<C*> nearby_cs*(C& obj);
}
B.cpp
#include "B.hpp"
#include "C.hpp"
std::vector<C*> B::nearby_cs*(C& obj) {
//do stuff
}
C.hpp
class A
class C {
void stuff();
}
C.cpp
#include "C.hpp"
#include "A.hpp"
void stuff() {
std::vector<C*> cs = A::getInstance().get_b()->nearby_cs(*this);
}
Problem:
3x Error: function random_int() is already defined in main.cpp. Files: C.cpp, A.cpp and B.cpp is not a problem caused because of a circular dependency, it is caused because you're defining the random_int() three times. It doesn't have anything to do with the classes.
Solution:
From this question, the possible solutions for your problem are:
Declare the function as static.
A.hpp
static int random int()
{
...
}
Declare the function as inline.
A.hpp
inline int random int()
{
...
}
Declare the function in the header (.hpp) file and define it in a source (.cpp) file.
A.hpp
...
int random_int();
...
A.cpp
...
int random_int(){
...
}
...
Additional information:
You have multiple typos with semicolons and braces.
Change this
int random_int() {
class C
to this
int random_int();
class C;
I presume the { and missing ; are simply typos.

Co-Dependent .h files with forward declaration

I have 3 classes (A, B & C) in different .h files. How can I move the #includes and forward declarations in order for it to compile.
Currently I've used forward declaration in A.h and thought it would work from there. Instead C.h is throwing many compiler errors of 'class A' is inaccessible with in this context.
// A.h
#pragma once
...
class B;
class A {
private:
B *parent_;
};
// B.h
#pragma once
...
#include <A.h>
class B : A {
public:
virtual void func(A *arg);
};
// C.h
#pragma once
...
#include <A.h>
#include <B.h>
class C : B {
public:
virtual void func(A *arg);
private:
A *left_child;
A *right_child;
};
The name A is private via B. You can either change to public or protected inheritance in B, or use (the fully-qualified name) ::A in C

Default constructor not called if classes devided into separate files

UPDATE:
Now I have this, and it does not compile:
A.h:
#ifndef A_H
#define A_H
class A {
private:
int foo;
public:
A();
int getfoo();
};
#endif
A.cpp:
#include "A.h"
A::A() {
foo = 5;
}
int A::getfoo(){
return foo;
}
B.h:
#ifndef B_H
#define B_H
class B {
private:
A myA;
public:
B();
int getAvalue();
};
#endif
B.cpp:
#include "A.h"
#include "B.h"
int B::getAvalue(){
return myA.getfoo();
}
Errors:
b.h line 6: C2146: missing ';' before identifier 'myA'
b.h line 6: C4430: missing type specifier - int assumed
b.h line 6: C4430: missing type specifier - int assumed
END UPDATE
I have written 2 classes in different cpp and header files: class A and class B.
Class B uses class A as a private variable and the default constructor of class A is never called.
Here is my code:
A.h:
class A {
public:
A();
int getfoo();
};
A.cpp:
class A {
private:
int foo;
public:
A();
int getfoo();
};
A::A() {
foo = 5;
}
int A::getfoo(){
return foo;
}
B.h:
class B {
public:
int getAvalue();
};
B.cpp:
#include "A.h"
class B {
private:
A myA;
public:
int getAvalue();
};
int B::getAvalue(){
return myA.getfoo();
}
classtest.cpp:
#include "stdafx.h"
#include <iostream>
#include "B.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
B stackB;
cout << stackB.getAvalue() << endl;
B* storeB = new B();
cout << storeB->getAvalue() << endl;
cin.get();
return 0;
}
The output is never 5 and the breakpoint inside the constructor A::A() is never triggered. It doesn't matter if I use B globally or locally. This sample works totally fine if I put the classes and functions in one single file.
If I add an empty default constructor to class B, the default constructor of class A gets called, but then Visual Studio 2008 complains about stack corruption around variable stackB.
What am I doing wrong?
Just with this class alone:
A.h:
class A {
public:
A();
int getfoo();
};
A.cpp:
class A {
private:
int foo;
public:
A();
int getfoo();
};
A::A() {
foo = 5;
}
int A::getfoo() {
return foo;
}
You are declaring class A in A.h.
Then in your implementation(cpp) file, you are then again declaring class A.
You are also forgetting to include A.h in A.cpp. If you included the header into the cpp; the compiler would of thrown out errors telling you what was wrong. You are also missing either header guards, or the pragma directive.
Your class should look like this:
A.h
#ifndef A_H
#define A_H
class A {
private:
int foo;
public:
A();
int getFoo() const; // const to return member and prevents modification
};
#endif // !A_H
A.cpp
#include "A.h" // you forgot to include the header
A::A() : // class constructor using it's member initializer list
foo( 5 ) {
}
int A::getFoo() const {
return foo;
}
Now once you fix your class, then working on class B should not be a problem. However there is one thing to be careful of when including a header file of one class into another; you can end up with circular includes. The best way to prevent that is to use a class prototype in the header and include its header in the containing class's cpp file. There are some cases where a class proto type will not work, but I'll leave that up to you to do the research.
How to use Class Prototype in C++
Class B might look like this:
B.h
#ifndef B_H
#define B_H
// #include "A.h" // uncomment this if prototype below doesn't work.
class A; // class prototype may not work in all cases;
// If the above prototype does not work; comment it out
// and replace it with #include "A.h".
class B {
private:
A myA;
public:
B(); // remove default
int getAValue() const;
};
#endif // !B_H
B.cpp
#include "B.h"
#include "A.h" // If class A's prototype in the header does not work
// then comment this out and place it in this class B's header by
// replacing it with the prototype.
B::B() {} // default constructor (should make this complete type)
int B::getAValue() const {
return myA.getFoo();
}
And this should help to fix your problems. If using the class prototype does not work in the header because in some cases it may not; you can remove the prototype declaration from the header and replace it with the include directive of that class and remove its include from the cpp file.

In C++, Can't I implement this classes without separating header and cpp?

Suppose I have "A.hpp", "B.hpp", and "main.cpp".
A.hpp
#ifndef _A_HPP_
#define _A_HPP_
#include "B.hpp"
class A {
public:
B& b_;
A(B& b) : b_(b) {
}
void foo() {
b_.foo();
}
};
#endif
B.hpp
#ifndef _B_HPP_
#define _B_HPP_
#include "A.hpp"
class B {
public:
A* a_;
B() : {
a_ = new A( *this );
}
void foo() {
}
};
#endif
main.cpp
#include "B.hpp"
#include "A.hpp"
int main()
{
B b;
b.a->foo();
return 0;
}
I know why I can't compile main.cpp but don't know how can I fix this situation without seperating header file and source file for classes A and B. ( For example situation , classes A and B are using template )
Thanks in advance. :)
If I understand you correctly - you want to be able to compile main.cpp without needing separate translation units for A and B, and without having to seprate-out A and B's interface and implementation?
You can do this - but you will still need to follow the rules for forward-declaration:
class B; // class `B` forward-declaration
// define class A, but don't implement the parts that need B's definition
class A {
public:
B& b_; // `A` can use `B` here, but the compiler still doesn't know how B is defined
A(B&& b); // also need to define A's structure, but not the method implementations
void foo();
};
class B {
public:
A* a_;
B() : {
a_ = new A( *this );
}
void foo() { }
};
// now we can define `A` using the `A::` syntax, instead of class{}:
A::A(B&& b) : b_(b) { }
void A::foo() { b_.foo(); }
int main()
{
B b;
b.a->foo();
return 0;
}

Slaying the Circular Dependence

I'm having a problem compiling with circular dependencies. I did some research, and people recommended using a forward declaration. I'm still having a problem with that because the class that has a forward declaration is using methods from the forwarded class. This causes the compiler to give me the error "Class A has incomplete field b". How can I get around the circular dependency where A requires B, and B requires A?
A.h:
#ifndef A_H_
#define A_H_
#include <iostream>
//#include "B.h"
class A
{
class B;
private:
B b;
public:
A();
~A();
void method();
};
#endif
A.cpp:
#include <iostream>
#include "A.h"
A::A()
{
}
A::~A()
{
}
void A::method()
{
b.method();
}
B.h:
#ifndef B_H_
#define B_H_
#include <iostream>
//#include "A.h"
class B
{
class A;
private:
A a;
public:
B();
~B();
void method();
};
#endif
B.cpp:
#include <iostream>
#include "B.h"
B::B()
{
}
B::~B()
{
}
void B::method()
{
a.method();
}
Your classes cannot work. Every A contains a B, which contains an A, which contains a B, etc., ad infinitum.
This will not work as you have constructed it as A requires full knowledge of the size of B and B requires the same of A, which is only given by seeing the full declaration.
The following is not valid:
class B;
class A {
B b;
};
Why? How much space do we allocate for an instance of A? sizeof(A) = sizeof(B) = undefined There is a workaround, however:
class B;
class A {
B* b_ptr;
B& b_ref;
};
This is perfectly valid, since the pointer and reference's size are known, regardless of the type they point to.
In at least one case (either A or B) you have to remove the dependence on the complete type. For example, below I've removed the need for A to have the complete type of B within the A.h header file:
// A.h
class B;
// B used as a reference only, so the complete type
// is not needed at this time
class A
{
public:
A(B& b) : b_(b) {}
void method();
private:
B& b_;
};
// A.cpp
// B is used, and the complete type is required
#include "B.h"
void A::f()
{
b.method();
}
You could try to replace one of the member by a pointer to the other class :
class B;
class A
{
private:
B* b;
public:
A();
~A();
void method();
};