Class A is the sole instantiator and container of instances of class B.
So it seemed like a good idea to make the constructor of class B private, and call it only by a friend function declared in class B and defined in class A.
File A.h (EDIT: included enum defined in class B)
#ifndef A_H
#define A_H
#include "B.h"
using namespace std;
class A
{ public:
A();
shared_ptr<B> CreateBInstance( const B::ENUM_STANDARD_COLORS );
shared_ptr<B> CreateBInstance( const string ); // Custom color
private:
unique_ptr<map<int, shared_ptr<B>>> UPTR__BInstancesMap;
}
#endif
File B.h (EDIT: included enum defined in class B)
#ifndef B_H
#define B_H
#include "A.h" // Causes chaos
using namespace std;
class B
{ public:
enum class ENUM_STANDARD_COLORS : unsigned int
{ ... // ~70 standard colors
};
private:
B();
friend
shared_ptr<B> A::CreateBInstance( const ENUM_STANDARD_COLORS );
friend
shared_ptr<B> A::CreateBInstance( const string ); // Custom color
}
#endif
Class A requires a full declaration (#include) of class B for shared_ptr<B>.
Class B requires some declaration of class A for the friend function.
A simple forward declaration causes the error:
invalid use of incomplete type 'struc A'
at the friend function declaration.
A full declaration (#include) is far worse:
error: prototype for 'std::shared_ptr A::CreateInstance()' does not match any in class 'A'
(but it does!) at the friend function declaration.
And, because class B is now broken:
error: 'B' was not declared in this scope
error: template argument 1 is invalid
appears at every mention of B in class A, as well as in classes F and G (etc.) which #include class B for their own use of shared_ptr<B>.
And, because classes F and G are also now broken:
error: 'F' was not declared in this scope
error: template argument 1 is invalid>
error: 'G' was not declared in this scope
error: template argument 1 is invalid
appears at every mention of F and G in class A.
Unfortunately, the include guards don't prevent the circular inclusion.
Is there a way to make this friend function work? I've never achieved so many errors in one go!
Class
Arequires a full declaration (#include) of classBforshared_ptr<B>.
No, forward declaration would be sufficient in A.h. shared_ptr (and unique_ptr) won't require class B to be complete type for return type declaration[1] and class data member declaration.
File A.h
#ifndef A_H
#define A_H
class B; // forward declaration
using namespace std;
class A
{ public:
A();
shared_ptr<B> CreateBInstance();
private:
unique_ptr<map<int, shared_ptr<B>>> UPTR__BInstancesMap;
};
#endif
[1] It's also true for "regular" type T which isn't shared_ptr.
In A header file, you can simply tell the compiler that an type B exists and it needs to look for it while linking. To do so, replace
#include "B.h"
by
class B;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With