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
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:
Make new friendships (A, B and further child classes should be friends of Create)
Use public constructors as mentioned by #Snps
Use an external class that only Base (and therefore also its friend, Create) can create and the rest can only copy. Idea from here.
Code for last solution:
#include <iostream>
using namespace std;
// Forward declaration
template<class T> T* Create(int i);
class Base {
class AccessKey {
friend class Base;
AccessKey() {};
public:
AccessKey(const AccessKey& o) {}
};
static AccessKey getAccessKey() { return AccessKey(); }
public:
template<class T>
friend T* Create(int);
virtual void say() = 0;
Base(int i, AccessKey k): i(i) { } // This can be public as it can be called without and AccessKey object
protected:
int i;
};
// Factory for Base class
template<class T>
T* Create(int i){
return new T(i, Base::getAccessKey());
}
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;
}
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
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() {}
// Factory for Base class
template<class T>
static T* Create(int i) {
static_assert(std::is_base_of<Base, T>::value, "Needs to be derived from Base");
return new T(i);
}
virtual void say() = 0;
protected:
Base(int i): i(i) { }
int i;
};
class A: public Base {
friend Base; // Allow Base to construct
public:
using Base::Base;
void say() { cout << "I am A and have a value of " << i << endl; }
};
class B: public Base {
friend Base; // Allow Base to construct
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 = Base::Create<A>(1);
a->say();
cout << "I'm creating B." << endl;
B* b = Base::Create<B>(2);
b->say();
return 0;
}
EDIT: Added static_assert
EDIT: Added link to run code
Related
Consider the following code
class A {
int x, y;
public:
A(){}
virtual void PrintSize(){ cout << sizeof(typeof(*this)) << endl; }
};
class B : public A {
int a, b, c;
public:
B(){}
};
int main() {
A obja;
B objb;
obja.PrintSize();
objb.PrintSize();
}
The intent of "PrintSize()" is to get the size of the current class where we are calling it from. What happens is that this-keyword refers to class A even though we are calling it from B. We don't want this since we need this function to be general for child classes.
We could obviously redefine the function verbatim to every class. The code would become harder to hande since there's so many unnesessary lines. Not to mention that re-writing the function to every class would defeat the purpose of deriving it in the first place.
Here's my temporary fix:
class A {
public:
virtual void PrintSize(){ cout << sizeof(typeof(*this)) << endl; }
};
class B : public A {
public:
virtual void PrintSize(){ cout << sizeof(typeof(*this)) << endl; }
};
class C : public A {
public:
virtual void PrintSize(){ cout << sizeof(typeof(*this)) << endl; }
};
class D : public A {
public:
virtual void PrintSize(){ cout << sizeof(typeof(*this)) << endl; }
};
While the accepted answer may have solved the immediate problem, you suddenly have no common base class for B and C. They inherit from two unrelated classes, namely A<B> and A<C>.
An alternative is to create a common base that defines an interface (called Interface below) and to add the CRTP class template between the derived classes and the interface. This lets you keep pointers and references to Interface and call the virtual member functions using those.
Here's an example of storing pointers to the common base class in a vector:
#include <iostream>
#include <memory>
#include <vector>
struct Interface {
virtual ~Interface() = default;
virtual void PrintSize() const = 0;
virtual void do_stuff() const = 0;
};
template<typename T>
struct Printer : public Interface {
void PrintSize() const override {
std::cout << sizeof(T) << '\n';
}
};
class B : public Printer<B> {
int a{};
public:
void do_stuff() const override { std::cout << "B doing stuff\n"; }
};
class C : public Printer<C> {
int a{}, b{}, c{};
public:
void do_stuff() const override { std::cout << "C doing stuff\n"; }
};
int main() {
std::vector<std::unique_ptr<Interface>> objs;
objs.emplace_back(std::make_unique<B>());
objs.emplace_back(std::make_unique<C>());
for(auto& ptr : objs) {
ptr->do_stuff();
ptr->PrintSize();
}
}
Possible output:
B doing stuff
16
C doing stuff
24
You can use the CRTP idiom to do this.
https://eli.thegreenplace.net/2011/05/17/the-curiously-recurring-template-pattern-in-c
The idea is the parent class is a template, so you can have access to the type of the child class directly in it.
With that, you'll be able to remove all "PrintSize" from child class.
Example :
template <typename Derived>
class A {
int x, y;
public:
A() {}
void PrintSize() { cout << sizeof(Derived) << endl; }
};
class B : public A<B> {
int a, b, c;
public:
B() {}
};
class C : public A<C> {
public:
C() {}
};
int main() {
C objc;
B objb;
objc.PrintSize();
objb.PrintSize();
}
The output is :
8
20
I have code which uses this design, simplifed to get this MCVE - code and compiler errors follow.
The basic problem is that I thought befriending the CRTP class would allow the templated base class access to the derived CRTP class's private members, including its private constructor.
But apparently it doesn't. Why?
this code on wandbox:
#include <iostream>
using namespace std;
template <class CRTP>
class Base
{
friend CRTP;
public:
static void Factory()
{
cout << "Base::Factory()" << endl;
CRTP x;
x.Hello();
}
virtual void Hello() { cout << "Base::Hello()" << endl; }
protected:
Base() { cout << "Base::Base()" << endl; }
virtual ~Base() { cout << "Base::~Base()" << endl; }
};
class Derived final : public Base<Derived>
{
public:
void Hello() override;
private:
Derived() { cout << "Derived::Derived()" << endl; }
~Derived() override { cout << "Derived::~Derived()" << endl; }
};
int main()
{
Derived::Factory();
// Expected output:
// Base::Factory()
// Base::Base()
// Derived::Derived()
// Derived::Hello()
// Derived::~Derived()
// Base::~Base()
}
And getting this compiler error (from clang 9.0.0, but gcc complains the same way):
prog.cc:12:12: error: calling a private constructor of class 'Derived'
CRTP x;
^
prog.cc:33:14: note: in instantiation of member function 'Base<Derived>::Factory' requested here
Derived::Factory();
^
prog.cc:27:3: note: declared private here
Derived() { cout << "Derived::Derived()" << endl; }
^
prog.cc:12:12: error: variable of type 'Derived' has private destructor
CRTP x;
^
prog.cc:28:11: note: declared private here
virtual ~Derived() { cout << "Derived::~Derived()" << endl; }
^
2 errors generated.
(FYI: Use case is I want the template base class to control lifetime - including construction - of the (CRTP) derived class instances via a static factory. So I want the derived classes to declare their constructors private, yet accessible to the parent's static factory method. This example shows the derived class instance created on the stack but the same errors occur if it is created in the heap (and returned).)
You've got the friend declaration in the wrong class. Derived needs to declare Base<Derived> as a friend, since a friend can access the private members. (A class declares another class to be a friend. A class does not declare itself as a friend of another class.)
You want to add
friend Base<Derived>;
into the Derived class declaration.
The concrete problem you are mentioning is that you placed the friend declaration in Base rather than in Derived.
The next problem is that Derived::Hello() has no implementation. If you don't need one (as in your example above) implement it only in Base and remove the virtual declaration. Derived will inherit it anyways.
The following works:
#include <iostream>
using namespace std;
template <class CRTP>
class Base
{
public:
static void Factory()
{
cout << "Base::Factory()" << endl;
CRTP x;
x.Hello();
}
void Hello() { cout << "Base::Hello()" << endl; }
protected:
Base() { cout << "Base::Base()" << endl; }
virtual ~Base() { cout << "Base::~Base()" << endl; }
};
class Derived final : public Base<Derived>
{
friend Base<Derived>;
/*^^^^^^ friend declaration goes here, not in Base */
Derived() { cout << "Derived::Derived()" << endl; }
~Derived() override { cout << "Derived::~Derived()" << endl; }
};
Output:
Base::Factory()
Base::Base()
Derived::Derived()
Base::Hello()
Derived::~Derived()
Base::~Base()
Currently, I have a based class with two different constructors:
class Base {
public:
Base(std::string filname){...}
Base(int a, int b) {...}
};
and a derived class of Base class. What I would like to do is to choose which constructor call inside the constructor of the derived class, but not in the initializer list. Something like this:
class Derived : public Base {
public:
Derived() {
if( /* exists("myFile") */ )
this->Base("myFile");
else
this->Base(1,2);
}
}
Is it possible to do that?, or because the base class is initialize before the derived class, the only way to call to the base constructor is in the initializer list?
Thanks
The choice of which base constructor is called happens before the body of the function and there's no way to change it at run time like that. However, you might be able to get close. If the base class also has a move constructor, or you could you add one, you could use that:
class Derived : public Base {
public:
Derived()
: Base{ exists("myFile") ? Base{"myFile"} : Base{1, 2} } {
}
}
This will call exists("myFile"); if that returns true, it will construct a temporary Base using the first constructor, and if it returns false it will construct a temporary Base using the second constructor. Either way, it will then construct the actual base subobject using this temporary.
You can simulate that by introducing a factory function:
class Base {
public:
Base(std::string filname);
Base(int a, int b);
};
class Derived : public Base {
Derived(std::string filname) : Base(filname) {}
Derived(int a, int b) : Base(a, b) {}
public:
static Derived create() {
if( /* exists("myFile") */ )
return Derived("myFile");
else
return Derived(1,2);
}
};
int main(){
auto d = Derived::create();
}
Alternatively, if derivation from Base is not required, an instance of Base can be held as a member (std::unique_ptr or std::aligned_storage) that you can initialise however you please.
Based on #DanielH comment in his answer I have developed an alternative solution which also works with abstract base classes in C++11:
#include <iostream>
struct Base {
Base(int x) {
std::cout << "Base x = " << x << std::endl;
}
Base() {
std::cout << "Base default" << std::endl;
}
virtual void foo() = 0;
};
struct Derived : Base {
struct TagA {};
struct TagB {};
Derived(bool condition)
: Derived(condition ? Derived{TagA()} : Derived{TagB()})
{}
void foo() override {}
private:
Derived(TagA dummy)
: Base(42)
{
std::cout << "Derived A dummy" << std::endl;
}
Derived(TagB dummy)
{
std::cout << "Derived B dummy" << std::endl;
}
};
int main() {
std::cout << "Construct Derived with false" << std::endl;
Derived x(false);
std::cout << "Construct Derived with true" << std::endl;
Derived y(true);
}
Is there a way to override separately functions with same names (from two parents) in a base class?
I am looking for something like this:
#include<iostream>
using namespace std;
class A {
public:
virtual void foo() {
cout << "A::Foo" << endl;
}
};
class B {
public:
virtual void foo() {
cout << "B::Foo" << endl;
}
};
class C : public A, public B {
public:
/*virtual void A::foo() {
cout << "C::Foo" << endl;
}*/
};
int main() {
C c;
c.A::foo(); // want to get C::Foo here
}
No you can't do this. If you want to avoid access to class A; via class C; explicit scope resolution make A private:
class C : private A, public B {
// ^^^^^^^
public:
};
If you want to prefer the implementation of A you can specify what you want to use explicitly:
class C : public A, public B {
public:
using A::foo();
};
Here is some sample code:
#include <iostream>
class A {
public:
virtual void foo() {
std::cout << "base" << std::endl;
}
A() {
foo();
}
};
class B : public A {
int a;
public:
void foo() {
std::cout << "derived" << std::endl;
}
B(int a) :
a(a) {}
};
int main() {
B o(1);
return 0;
}
I want foo() to get called every time some A derived object is constructed. I do not want to call foo() explicitly in every derived class constructor.
Is there a way to do this in some elegant way?
There is no way you can call an overridden foo() from a base class constructor, no matter what you do. When the base class constructor is called, the derived class object has not been constructed yet, so you cannot call any of its methods or access any of its members. This is true for virtual functions and regular functions as well. In a base class constructor, the this pointer is pointing at the base class, not the derived class.
A potential workaround is to delegate construction to a separate function that clients will have to call instead. Then have that function call foo after construction:
class A {
public:
virtual void foo() {
std::cout << "base" << std::endl;
}
template<typename T, typename ... Args>
static T construct(Args ... args)
{
T newT{ args... };
newT.foo();
return std::move(newT);
}
protected:
A() {
//Construct A
}
};
class B : public A {
int a;
public:
void foo() {
std::cout << "derived" << std::endl;
}
B(int a) :
a(a) {}
};
int main()
{
B o = A::construct<B>(1);
A a = A::construct<A>();
return 0;
}