Slaying the Circular Dependence - c++

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();
};

Related

Bilateral friend functions in C++: how to make it compile?

I have the following C++ files:
A.h
#ifndef A_H
#define A_H
#include "B.h"
class A
{
private:
int m_a;
public:
A();
void a(const B &b);
friend void B::b(const A &a);
};
#endif // A_H
A.cpp
#include "A.h"
#include "B.h"
#include
A::A()
{
m_a = 100;
}
void A::a(const B &b)
{
std::cout << b.m_b << ".\n";
}
B.h
#ifndef B_H
#define B_H
class A;
class B
{
private:
int m_b;
public:
B();
void b(const A &a);
friend void A::a(const B &b); // error: invalid use of incomplete type 'class A'
};
#endif // B_H
B.cpp
#include "B.h"
#include
#include "A.h"
B::B()
{
this->m_b = 101;
}
void B::b(const A &a)
{
std::cout << a.m_a << ".\n";
}
When I try to compile this, it gives me:
error: invalid use of incomplete type 'class A'.
How should I fix this?
It is not possible to have a member functiion of B a friend of A and a member function of A a friend of B.
There are several ways to overcome this.
Write one or both functions as non-members. Make them friends of both classes if neseccary.
Make the entire class a friend of the other class. If that's too broad a permission, extract a smaller class to serve as a friend.
Turn both classes into class templates (the template parameter does not matter).
enum unit {u};
template <unit X> class A;
template <unit X> class B
{
static void foo() {}
static void bar() { A<X>::foo(); }
friend void A<X>::bar();
};
template <unit X> class A
{
static void foo() {}
static void bar() { B<X>::foo(); }
friend void B<X>::bar();
};
using AX = A<u>;
using BX = B<u>;
Actually in your case, your are creating a circular dependency.
It is generally avoided with forward declaration but as far as i know C++ doesn't let us to do forward declaration for member functions so it seems impossible now to me.
But it is possible to break circular dependency when you declare class as friend.
a.h
#ifndef A_H
#define A_H
#include "b.h"
class B;
class A
{
private:
int m_a;
public:
A();
void a(const B &b);
friend class B;
};
#endif // A_H
a.cpp
#include "a.h"
#include "b.h"
#include <iostream>
A::A()
{
m_a = 100;
}
void A::a(const B &b)
{
std::cout << b.m_b << ".\n";
}
b.h
#ifndef B_H
#define B_H
class A;
class B
{
private:
int m_b;
public:
B();
void b(const A &a);
friend class A;
};
#endif // B_H
b.cpp
#include "b.h"
#include "a.h"
#include <iostream>
B::B()
{
this->m_b = 101;
}
void B::b(const A &a)
{
std::cout << a.m_a << ".\n";
}
You are trying to setup a circular dependency. This is a terrible thing to handle and it is simply forbidden in plenty of use cases. In C++, the rule is that you can use any object as soon as it is declared, even if it is fully defined later. The problem is that members are only declared by the definition of a class. So if one class (say B) needs to use is its definition members of another class (say A), then A has to be defined before B. As you cannot have A defined before B and B defined before A at the same time, you will not be able to achieve what you want in C++.
If you find yourself trying to setup a member of A as friend in B and a member of B as friend in A, then you have a general design problem. If it makes sense (on a model point of view) it can be solved by making one full class as friend (this is #zmb's answer), or changing the member functions to non members. But I strongly advise you to go back one step and try to build a hierachical model instead of a circular one. Unfortunately, it becomes a design question and not a programming one, so I am afraid I shall not be able to help you more in SO...
You are using an unknown type:
friend void A::a(const B &b);
The compiler only knows that the class A exists, but nothing else.
You can declare the entire class A as a friend instead:
friend class A;

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;
}

Circular inclusion issue with extended class c++

Can you figure out how to solve this circular inclusion problem?
C extends B and B includes A. A includes C. Every forward declaration I tried hasn't worked.
Errors
Error 1 error C2504: 'B' : base class undefined
Error 2 error C3668: 'C::c' : method with override specifier 'override' did not override any base class methods
File A.h:
#pragma once
#include "C.h"
struct A
{
A();
C c;
};
File B.h:
#pragma once
#include "A.h"
struct A;
struct B
{
virtual void c() = 0;
A* a;
};
File C.h:
#pragma once
#include "B.h"
struct B;
struct C : public B
{
void c() override;
};
The solution is always the same and it looks like you were on the right track. However, you're not using forward declartions correctly. There should be many examples of how to do this for example here.
B.h
// Why are including "A.h" here, this is causing your circular include
// issue, it needs to be moved to your implementation (e.g., "B.cpp")
#include "A.h"
struct A; // Forward declaration, good
struct B
{
virtual void c() = 0;
A* a; // A pointer only requires the above forward declartion
};
C.h
#include "B.h" // Necessary since you're extending `B`
struct B; // This forward declaration is superfluous and should be removed
struct C : public B
{
void c() override;
};

construct an object of B in constructor of class A

Here is what I am trying to do, I want the class A's constructor to call B's constructor for an object of B, like this main()->A->B
A.cpp:(included B.h)
A::A(){
B foo;
}
B.h:
class B{
B(){//some code};
};
but GCC won't compile and says A::B foo has initializer but incomplete type. I am guessing the compiler saw no local class of B defined in A, so it complained and didn't know the Class B was from another file. My question is how to construct an B's object in A's constructor like above.I am sure I am missing some fundamentals about C++, please bear with me. Thank you in advance.
Try
class A
{
public:
A(); // Don't define A::A() here
// As the compiler has not seen B
};
class B
{
public:
B() {}
};
// At this point both classes have been seen
A::A()
{
::B foo; // So now you can use B
// Note I am using ::B here
// As the error message suggests that you have some class B defined
// Within A which is confusing it. the prefix :: means take the class
// B from the global scope rather than a closer scope.
}
You do not have any class of type A::B. From your comment, it looks like you are trying to use a pointer to B by calling it A::B *. This is incorrect. A pointer to B is always B *, regardless of where it appears. From what you said, it looks like you want something like this:
a.hpp
#ifndef A_HPP_
#define A_HPP_
class B;
class A {
public:
A(B * b);
private:
B * my_very_own_b;
};
#endif // A_HPP_
a.cpp
#include "a.hpp"
#include "b.hpp"
A::A(B * b):
my_very_own_b(b)
{
}
b.hpp
#ifndef B_HPP_
#define B_HPP_
class B {
public:
B();
private:
int x;
};
#endif // B_HPP_
b.cpp
#include "b.hpp"
B::B():
x(0)
{
}
main.cpp
#include "a.hpp"
#include "b.hpp"
int main() {
B b;
A a(&b);
return 0;
}

In C++, I want two classes to access each other

I have two classes, class A and class B.
A.h -> A.cpp
B.h -> B.cpp
And then, I set B as a member in class A. Then, class A can access class B by
#include <B.h>
But, how can I get the pointer of class A in class B and access the public member of class A?
I found some information about on the internet: a Cross-class. They said you can make it by setting the class B as a nested class in class A.
Do you have any other advice?
sorry.
myCode: as follow..
class A:
#ifndef A
#define A
#include "B.h"
class A
{
public:
A() {
b = new B(this);
}
private:
B* b;
};
#endif
#ifndef B
#define B
#include"A.h"
class B
{
public:
B(A* parent = 0) {
this->parent = parent;
}
private:
A* parent;
};
#endif
Just use forward declaration. Like:
A.h:
#ifndef A_h
#define A_h
class B; // B forward-declaration
class A // A definition
{
public:
B * pb; // legal, we don't need B's definition to declare a pointer to B
B b; // illegal! B is an incomplete type here
void method();
};
#endif
B.h:
#ifndef B_h
#define B_h
#include "A.h" // including definition of A
class B // definition of B
{
public:
A * pa; // legal, pointer is always a pointer
A a; // legal too, since we've included A's *definition* already
void method();
};
#endif
A.cpp
#inlude "A.h"
#incude "B.h"
A::method()
{
pb->method(); // we've included the definition of B already,
// and now we can access its members via the pointer.
}
B.cpp
#inlude "A.h"
#incude "B.h"
B::method()
{
pa->method(); // we've included the definition of A already
a.method(); // ...or like this, if we want B to own an instance of A,
// rather than just refer to it by a pointer.
}
Knowing that B is a class is enough for compiler to define pointer to B, whatever B is. Of course, both .cpp files should include A.h and B.h to be able to access class members.