Class method friend of another class in two separate files

Class method friend of another class in two separate files



My goal is simple - I want to access the protected members of one class from the methods of another class. For this I have the following -



A.HPP


#ifndef A_HPP
#define A_HPP

#include "B.hpp"
using namespace std;

class A

protected:
int a;
public:
A();
~A();
friend void B::geta(A& ao);
;

inline A::A()

a = 2;
cout << a;


#endif



B.HPP


#ifndef B_HPP
#define B_HPP

using namespace std;

class A;

class B

protected:
int b;
public:
B();
~B();
void geta(A& ao);
;

inline B::B()

b = 1;
cout << b;


inline void B::geta(A& ao)

b = ao.a;
cout << b;


#endif



MAIN.CPP


#include <iostream>

#include "A.hpp"
#include "B.hpp"

int main()

A ao;
B bo;
bo.geta(ao);
return 0;



When I compile this I get the following error.



error



How do I fix this? Most answers that I see here are just putting all classes in one file and defining functions in appropriate positions to achieve this but I need them in separate files.






if already in hpp file, why dont you move implementations inside the class

– macroland
Sep 14 '18 at 4:29






@macroland That actually won't solve the problem

– πάντα ῥεῖ
Sep 14 '18 at 4:31






@User525412790 Aside note: Don't post compiler errors as images, but rather provide them as text. This will make your question more useful with future research by other users.

– πάντα ῥεῖ
Sep 14 '18 at 4:50




2 Answers
2



Option 1: Not inline



You can of course move the definition of B::geta to a B.cpp file which includes A.hpp and remove the inline keyword. But this might make compiler optimizations less likely.


B::geta


inline



Option 2: Weird #include logic


#include



Your definitions as they are can only compile if the compiler sees a forward declaration of A, the definition of B, the definition of A, and the definition of B::geta, all in that order. So if you want the definition of A in one file and the definition of B in another, you'll need to get the preprocessor to do some switching back and forth between files.


A


B


A


B::geta


A


B


// NO A_HPP include guard!
#ifdef INCLUDED_FROM_B_HPP

class A

protected:
int a;
public:
A();
~A();
friend void B::geta(A& ao);
;

inline A::A()

a = 2;
cout << a;


#else
# include "B.hpp"
#endif


#ifndef B_HPP
#define B_HPP

class A;

class B

protected:
int b;
public:
B();
~B();
void geta(A& ao);
;

#define INCLUDED_FROM_B_HPP
#include "A.hpp"
#undef INCLUDED_FROM_B_HPP

inline B::B()

b = 1;
cout << b;


inline void B::geta(A& ao)

b = ao.a;
cout << b;


#endif



So now if a file does #include "B.hpp", the preprocessor will:


#include "B.hpp"


class A;


B


INCLUDED_FROM_B_HPP


INCLUDED_FROM_B_HPP


B



If a file does #include "A.hpp" first, things are a bit trickier:


#include "A.hpp"


INCLUDED_FROM_B_HPP


class A;


B


INCLUDED_FROM_B_HPP


#include "A.hpp"


INCLUDED_FROM_B_HPP


INCLUDED_FROM_B_HPP


B



Option 3: friend class B;


friend class B;



Instead of specifying just the one member function B::geta to friend, just befriend the class itself, with the declaration friend class B;. Now A.hpp doesn't need to include B.hpp, so there's no circular dependency issue.


B::geta


friend class B;



This doesn't much decrease encapsulation from the point of view of what access is and isn't possible, since normally any programmer who can modify any part of class B can also modify B::geta. But it does open possibilities of "accidentally" using non-public members of A in other members of B.


class B


B::geta


A


B



Option 4: Refactor access method


#ifndef A_HPP
#define A_HPP

class B;

class A

protected:
int a;
public:
A();
~A();

class AccessForB
private:
static int geta(A& aobj) return aobj.a;
friend class ::B;
;
;

inline A::A()

a = 2;
cout << a;


#endif



...


inline void B::geta(A& ao)

b = A::AccessForB::geta(ao);
cout << b;



This code introduces a new sort of encapsulation: now class B can only get the value from member a, can't modify that value, and can't access any other non-public members of A. Additional accessors could be added for other members as appropriate. To permit modifying a member, the class could either provide "set" accessors, or an accessor that returns a reference. For non-public functions, the class could provide wrapper functions that just pass through to the actual function.


class B


a


A



It's still true that it's possible for members of B other than B::geta to exploit the friendship, but now typing out A::AccessForB:: can't really be considered an accident.


B


B::geta


A::AccessForB::



... but I need them in separate files.



Move the inlined functions out to a separate B.cpp file that #include's A.hpp.


B.cpp


#include


A.hpp



As being just seen as a forwarded class declaration A's declaration isn't yet complete at the point you're starting to use it in B.hpp, and the compiler complains about that righteously.


A


B.hpp



You can still retain the inline keyword, the compiler will respect it as a hint as usual.


inline



Here's the sketch:



B.hpp


#ifndef B_HPP
#define B_HPP

using namespace std;

class A;

class B

protected:
int b;
public:
B();
~B();
void geta(A& ao);
;
#endif



B.cpp


#include "B.hpp"
#include "A.hpp"

inline B::B()

b = 1;
cout << b;


inline void B::geta(A& ao)

b = ao.a; // <<<<<<<<<<<< here's the problem to be solved
cout << b;



These questions and answers are very much related to your problem:






Can I not move the definitions to a hpp file say A_impl.hpp and B_impl.hpp instead? I will have lot of these files and I don't want to generate avoidable object files?

– Donovan
Sep 14 '18 at 4:36


hpp


A_impl.hpp


B_impl.hpp






@User525412790 No you can't. All #include statements will be resolved prior to any actual compilation by the preprocessor. The linking stage might respect ìnline keywords as much as possible thoogh.

– πάντα ῥεῖ
Sep 14 '18 at 4:38



#include


ìnline






This won't work, assuming some other translation unit will need to odr-use one of those member functions.

– aschepler
Sep 14 '18 at 4:58






@aschepler What do you mean won't work? inlining the functions in question?

– πάντα ῥεῖ
Sep 14 '18 at 5:01







@ πάντα ῥεῖ : Were you able to execute it? My A and B cpp files compile and then I create a .a file with those but I get linking errors when I try to execute main()

– Donovan
Sep 14 '18 at 5:01


.a


main()



Thanks for contributing an answer to Stack Overflow!



But avoid



To learn more, see our tips on writing great answers.



Required, but never shown



Required, but never shown




By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

How do I collapse sections of code in Visual Studio Code for Windows?

ャフサォクコ ケウ,コ,ワ メ,ロスョノ゙,クネ,フムカヤヲニ,エコ゚ツ ウイオン゙ケワサネォキモュキォウイノンコチ゚メヌナイゥフュ,カヒウネェ ネ,ホノケ,ムュキ ッボーミュハ,チ ツス ィ メウイマヤ,゙ウチ ヅ ロ,ォジヌェ ャヌット ェ,マャ,チナエヒネソキツテ トホヲヲミーァ