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]
A constructor so declared has the same access as the corresponding constructor in
X
. ...
You can fix the error if you explicitly add constructors to derived classes instead of inheriting them from Base
.
A(int i) : Base(i) {}
and
B(int i) : Base(i) {}
Live demo
Another solution, of course, is to make Base
's constructor public
. You could also make its destructor protected
, but it's not necessary since the class cannot be instantiated anyway due to the pure virtual member function.
class Base {
public:
template<class T>
friend T* Create(int);
virtual void say() = 0;
Base(int i): i(i) { } // This won't compile
int i;
protected:
~Base() {}
};
Live demo
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