I want to define two classes, A and B. A has a data member which is a Class B object and is in-class initialised. A also has a method to retrieve the value in this B type data member and this method would be declared as a friend method in B. Here is my code:
class A{
public:
int getBValue();
private:
B b=B(1);
};
class B{
public:
friend int A::getBValue();
B(int i):value(i){}
private:
int value;
};
int A::getBValue(){
return b.value;
}
And unsurprisingly the compilation had failed because of unknown type B in class A definition. I had tried to swap the definitions of A and B in the source and the result was even worse. Is there a possible way to resolve this cross reference issue between A and B?
If this is the complete code as you have it, then the problem is that the compiler doesn't know what a B is at the time it is compiling class A. One way to solve it is by creating a pointer to B instead of having a B itself:
A.h
#ifndef CLASS_A
#define CLASS_A
class B;
class A{
public:
int getBValue();
private:
B *b;
};
#endif
B.h
#ifndef CLASS_B
#define CLASS_B
#include "A.h"
class B{
public:
friend int A::getBValue();
B(int i):value(i){}
private:
int value;
};
#endif
A.cpp
#include "A.h"
#include "B.h"
int A::getBValue(){
return b->value;
}
Replacing an embedded member of type B with a pointer (or reference) to a B changes the way your class works and needs additional care when copying objects of class A.
When you reverse the definitions, you cannot make a member function of class A a friend of class B, because the type of A is incomplete at the time of the friend declaration. But you can make the entire class A a friend.
A solution with class A having an embedded member of class B could look like this:
class A;
class B{
public:
friend class A;
B(int i):value(i){}
private:
int value;
};
class A{
public:
int getBValue();
private:
B b=B(1);
};
int A::getBValue(){
return b.value;
}
Changes made:
Declared B before A. A forward declaration for A is used.
Made the class A a friend of B. This works even when A is not yet fully defined.
Compiles with g++ version 4.7.2 (-std=c++11 needed for B b=B(1);)
Anyway, having a member of class A accessing a private member of class B is something which can (and should) almost always be avoided (see Laszlo Papp's comment on your post).
Related
I've got the following class structure. This obviously won't compile. I can forward declare B. Then, I can either use function pointers in function calls but it's not a nice solution, as I would call other other functions in A from A::funcA or put part of the declaration of B into a header, which would be a few hundreds of lines and would be practical.
What (else) would be the preferred way to handle this situation?
class B;
class A
{
public:
void funcA(B* b);
double funcA2();
int funcA4(B* b);
private:
E memberA1;
E memberA2;
};
void A::funcA( B* b) {
b->funcB(a->memberA1, a->memberA2);
class B : public BBase
{
public:
void FuncB(E* e1, E* e2)
{
/* using const objects of B that are initialized
by B() and some other functions... */
}
std::vector<C*> memberB1; // C has std::vector<A*> memberC1
};
int main() {
calling B->memberB1.at(0)->memberC1.at(0)->funcA();
}
I have the the following (omitting some unneccesary lines):
A.h
Class B;
Class A {
declaration of A
};
A.cpp ....
B.h
#include "A.h"
#include "BBase.h"
Class B {
declaration of B
};
B.cpp ....
BBase.h
#include "C.h"
#include "A.h"
#include "AInterface.h"
typedef std::vector<AInterface> AList;
BBase {
declaration of abstract BBase
};
BBase.cpp ....`
But I still get error: member access into incomplete type 'B'.
Assuming E and C are adequately declared/defined, then what you have is almost fine. The problem is that you define the member function of A before you have the definition of the B class, make sure that class B is fully defined (the actual class, not the full implementation of its member functions) before you you have the A member functions implemented.
So something like this:
class B;
class A { ...; void member_function(B*); ... };
class B { ...; void other_member_function(); ... };
void A::member_function(B* b) { ...; b->other_member_function(); ... }
I would suggest to use either the Interface instead of concrete B class
class B : public IB{
};
and pass IB instead of B to A.
either even better in c++ use a template function and bind your member function which you want to call
a.funcA( std::bind( &B::funcB, &b, someArg );
So, I want something like:
class A{
B member;
};
class B{
A function();
};
No matter in which order I declare them, I get an incomplete type error (and I pretty much understand why).
How can I solve this? I don't want to use pointers or to have the function defined outside the B class. Also, declaring them before as
class A; class B;
doesn't seem to work either.
No need for class definition when declare a function.
class A;
class B{
A function();
};
class A{
B member;
};
This order will work:
class A;
class B {
A function();
};
class A {
B member;
};
My title sounds a little weird...
But my question is...
class A{
public:
doSomething(B & b);
}
class B{
public:
doSomething(A & a);
}
is this not supposed to work??
I get errors saying function does not take 1 parameter
because the identifier (classes) is undefined...
A type needs to be declared before it can be used. Since you have an interdependency between classes you need to use a forward declaration.
class B; // Forward declaration so that B can be used by reference and pointer
// but NOT by value.
class A{ public: doSomething(B & b); }
class B{ public: doSomething(A & a); }
Note that this is generally considered a very bad design and should be avoided if possible.
class A{
public:
doSomething(B & b);
};
is not ok , because the compiler is yet to know what B is , which is defined latter.
Compiler Always works from a top-down approach , so it must have seen a class (either declared or defined) , before it is being used elsewhere , so your code should be
class A; // Not reqd in your case , but develop a good programming practice of using forward declaration in such situations
class B; // Now class A knows there is asnothed class called B , even though it is defined much later , this is known as forward declaration
class A{
public:
doSomething(B & b);
}
class B{
public:
doSomething(A & a);
}
I'm trying to force function caller from a specific class.
For example this code bellow demonstrate my problem.
I want to make 'use' function would be called only from class A.
I'm using a global namespace all over the project.
a.h
#include "b.h"
namespace GLOBAL{
class A{
public:
void doSomething(B);
}
}
a.cpp
#include "a.h"
using namespace GLOBAL;
void A::doSomething(B b){
b.use();
}
b.h
namespace GLOBAL{
class B{
public:
friend void GLOBAL::A::doSomething(B);
private:
void use();
}
Compiler says:
‘GLOBAL::A’ has not been declared
‘void GLOBAL::B::use()’ is private
Can anyone help here ?
Thanks a lot,
Mike.
This is because in the friend delcaration you are refering to a member of a class.
For this to work the compiler must already have seen the full definition of A.
a.h
// #include "b.h" // remove this line it is not needed.
namespace GLOBAL{
class B; // Forward declare the class here.
class A{
public:
void doSomething(B&); // Note: This should probably be a reference.
// Change to doSomething(B&);
}
}
b.h
// Add this line it is needed for the friend declaration.
// To have a member as a friend we need the definition of 'A'
#include "a.h"
namespace GLOBAL{
class B{
public:
friend void GLOBAL::A::doSomething(B&);
private:
void use();
}
a.cpp
#include "a.h"
// Add this line to include the B definition so you know how to call use()
#include "b.h"
using namespace GLOBAL;
void A::doSomething(B& b){ // b should be a reference otherwise you are copying it.
b.use();
}
The following compiles fine from a cpp file:
namespace GLOBAL
{
class B;
class A
{
public:
void doSomething(B& b);
};
};
namespace GLOBAL
{
class B
{
public:
friend void GLOBAL::A::doSomething(B&);
private:
void use()
{
}
};
};
void GLOBAL::A::doSomething(B& b)
{
b.use();
}
As best I can tell your problem arises from the fact that you include "b.h" from "a.h" that defines the B class before the A class is defined yet the B class makes a reference to the A class. So you have problems. However you can't forward declare an object of type B because you are copying via the stack. Hence why I use a reference to class B (as this doesn't require the B object to be known in advance).
Basically you have some fundamental problems with your structure that needs working out. You need to do some reading up on forward declarations and circular dependencies
Edit: Specifying purely that class A is a friend of B (rather than a specific function in A that references B) is actually a possibility as the friend definition provides a kind of forward declaration. As such the following code compiles:
namespace GLOBAL
{
class B
{
public:
friend class A;
private:
void use()
{
}
};
};
namespace GLOBAL
{
class A
{
public:
void doSomething(B b);
};
};
void GLOBAL::A::doSomething(B b)
{
b.use();
}
As such in your code, originally posted, chaging the friend statement to, simply
friend class A;
should allow your code to compile.
Move #include "b.h" from a.h to a.cpp after the first #include directive. The compiler doesn't need to see the friend declaration until it's compiling the function that the declaration applies to.
#include <iostream>
class B;
class A{
int a;
public:
friend void B::frndA();
};
class B{
int b;
public:
void frndA();
};
void B::frndA(){
A obj;
std::cout << "A.a = " << obj.a << std::endl;
}
int main() {
return 0;
}
When trying to compile this code, some errors occurred. E.g.
invalid use of incomplete type
What are the problems in this code?
Place the whole of the class B ... declaration before class A. You haven't declared B::frndA(); yet.
#include <iostream>
using namespace std;
class B{
int b;
public:
void frndA();
};
class A{
int a;
public:
friend void B::frndA();
};
void B::frndA(){
A obj;
//cout<<"A.a = "<<obj.a<<endl;
}
int main() {
return 0;
}
The problem is you can't friend a member function before the compiler has seen the declaration.
You are going to need to rearrange your code to solve the problem (i.e. move the definition of class B prior to class A).
You need to put the declaration of B before A. The compiler doesn't know about this: B::frndA(). A forward declaration is not enough information to infer what members the type has.
I would recommend to put your class A declaration in a file A.h and it's definition inside a file A.cpp. Likewise the same for the type B inside of B.h and B.cpp
At the top of each header file put #pragma once (or if you prefer include guards).
Then inside your B.h you can simply include A.h.