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

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;

Related

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.

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

Access member of class from a constructor of another class

My code looks something like this:
main.cpp
#include <iostream>
#include "A.h"
#include "B.h"
using namespace std;
int main(){
int d,f;
A c();
d = c.GetStuff();
B *d = new C();
f = d->Get();
return 0;
}
A.h
#ifndef A_H
#define A_H
class A
{
int a;
public A();
int GetStuff() {return(a) ;}
};
#endif
A.cpp
#include "A.h"
A::A()
{
a = 42;//just some value for sake of illustration
}
B.h
#ifndef B_H
#define B_H
Class B
{
public:
virtual int Get(void) =0;
};
class C: public B {
public:
C();
int Get(void) {return(a);}
};
#endif
B.cpp
#include "B.h"
C::C() {
a // want to access this int a that occurs in A.cpp
}
My question is, what is the best way to gain access to "a" in B.cpp?
I tried using class "friend", but I am not getting results.
Any suggestions?
Thanks!
Two different answers, depending on what you mean
If each A object is meant to have it's own unique 'a' variable (which is how you've defined it) then you'll need to pass an A into the constructor of C:
C::C(const A &anA) {
int foo= anA.a; //
}
And, invoking the constructor becomes:
A myA;
B *myC = new C(myA); // You picked confusing names for your classes and objects
However, if you intended all A objects to share a common a value, then you should declare a and getStuff as static in A :
class A
{
static int a;
public:
static int GetStuff() {return a;};
... and access it as A::GetStuff() in the C constructor.

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.