I'm trying to create a factory for derived classes. I only want the factory to be able to create instances of the derived classes so I've made the base constructor protected
; the derived classes just use the base class constructors so their constructors are protected
also.
I tried to declare the factory as a friend of the base class so that it could access the protected
constructor. When I compile using this command
clang++ -std=c++11 -stdlib=libc++ Friends.cpp -o Friends
I get this error:
Friends.cpp:23:20: error: calling a protected constructor of class 'A'
return new T(i);
^
Friends.cpp:42:16: note: in instantiation of function template specialization 'Create<A>' requested
here
A* a = Create<A>(1);
^
Friends.cpp:30:25: note: declared protected here
using Base::Base;
^
Along with a similar error for derived class B
.
I get the feeling from reading other questions on stackoverflow.com, that this isn't possible in C++11, but I'm not sure why. Can someone explain why this won't work and perhaps an alternative?
Example code
#include <iostream>
using namespace std;
// Forward declaration
template<class T> T* Create(int i);
class Base {
public:
template<class T>
friend T* Create(int);
virtual void say() = 0;
protected:
Base(int i): i(i) { } // This won't compile
int i;
};
// Factory for Base class
template<class T>
T* Create(int i){
return new T(i);
}
class A: public Base {
public:
using Base::Base;
void say() { cout << "I am A and have a value of " << i << endl; }
};
class B: public Base{
public:
using Base::Base;
void say() { cout << "I am B and have a value of " << i << endl; }
};
int main(){
cout << "I'm creating A." << endl;
A* a = Create<A>(1);
a->say();
cout << "I'm creating B." << endl;
B* b = Create<B>(2);
b->say();
return 0;
}
When you inherit a constructor from a base class it retains the access of the original constructor, regardless of where you place the
using
declaration in the derived class.From §12.9/4 [class.inhctor]
You can fix the error if you explicitly add constructors to derived classes instead of inheriting them from
Base
.and
Live demo
Another solution, of course, is to make
Base
's constructorpublic
. You could also make its destructorprotected
, but it's not necessary since the class cannot be instantiated anyway due to the pure virtual member function.Live demo
Friendship does not go down the inheritance tree. Create is friend of Base, and therefore can not access the protected A::A(int) and B::B(int).
Possible solutions include:
Create
)Base
(and therefore also its friend,Create
) can create and the rest can only copy. Idea from here.Code for last solution:
I would be tempted to make the
Create()
function a static member of Base and then just make all the derived classes friends of Base:Run This
EDIT: Added static_assert
EDIT: Added link to run code