Inheritance in curiously recurring template pattern polymorphic copy (C++) - c++

I'm using CRTP to add a clone method to inherited classes, for example:
class Base
{
virtual ~Base() {};
virtual Base* clone() const = 0;
};
template<class Derived> class BaseCopyable : Base
{
public:
virtual Base* clone() const
{
return new Derived(static_cast<Derived const&>(*this));
}
};
class A : public BaseCopyable<A>;
class B : public BaseCopyable<B>;
etc...
But if I have a class that inherits from B, for example:
class differentB : public B;
Then clone() doesn't return an object of type differentB, it returns a B. Besides writing a new clone() method in differentB, is there some way to fix this?
Thanks for reading!

This is a rework of my answer to this question
Your intent is to have all the derived classes in your hierarchy
inherit cloneability (polymorphic copy) from their base class so
that you do not also need to provide each of them with an override
of clone(), but your attempted CRTP solution with class template
BaseCopyable can only only confer cloneability in this way upon
classes immediately derived from Base, and not upon classes derived
from such derived classes.
I do not think it is not possible to propagate cloneability right down an
arbitrarily deep hierarchy by confering cloneability "just once" at
the topmost concrete classes. You must explicitly confer it on each
concrete class, but you can do this via their base classes and
without repetitiously overriding clone(), by using a CRTP
template that relays cloneability from parent class to child in the
hierarchy.
Clearly, a CRTP template that fits this bill will differ from BaseCopyable
by requiring two template parameters: the parent type and the child type.
A C++03 solution is as illustrated by the following program:
#include <iostream>
// As base of D, this makes D inherit B and makes D cloneable to
// a polymorphic pointer to B
template<class B, class D>
struct cloner : virtual B
{
virtual B *clone() const {
return new D(dynamic_cast<D const&>(*this));
}
virtual ~cloner() {}
};
struct Base
{
virtual ~Base() {
std::cout << "I was a Base" << std::endl;
};
virtual Base* clone() const = 0;
};
struct A : cloner<Base,A> // A inherits Base
{
virtual ~A() {
std::cout << "I was an A" << std::endl;
};
};
struct B : cloner<Base,B> // B inherits Base
{
virtual ~B() {
std::cout << "I was a B" << std::endl;
};
};
struct DB : cloner<B,DB> // DB inherits B, Base
{
virtual ~DB() {
std::cout << "I was a DB" << std::endl;
};
};
int main()
{
Base * pBaseA = new A;
Base * pBaseB = new B;
Base * pBaseDB = new DB;
Base * pBaseCloneOfA = pBaseA->clone();
Base * pBaseCloneOfB = pBaseB->clone();
Base *pBaseCloneOfDB = pBaseDB->clone();
B * pBCloneOfDB = dynamic_cast<B*>(pBaseDB->clone());
std::cout << "deleting pBaseA" << std::endl;
delete pBaseA;
std::cout << "deleting pBaseB" << std::endl;
delete pBaseB;
std::cout << "deleting pBaseDB" << std::endl;
delete pBaseDB;
std::cout << "deleting pBaseCloneOfA" << std::endl;
delete pBaseCloneOfA;
std::cout << "deleting pBaseCloneOfB" << std::endl;
delete pBaseCloneOfB;
std::cout << "deleting pBaseCloneOfDB" << std::endl;
delete pBaseCloneOfDB;
std::cout << "deleting pBCloneOfDB" << std::endl;
delete pBCloneOfDB;
return 0;
}
The output is:
deleting pBaseA
I was an A
I was a Base
deleting pBaseB
I was a B
I was a Base
deleting pBaseDB
I was a DB
I was a B
I was a Base
deleting pBaseCloneOfA
I was an A
I was a Base
deleting pBaseCloneOfB
I was a B
I was a Base
deleting pBaseCloneOfDB
I was a DB
I was a B
I was a Base
deleting pBCloneOfDB
I was a DB
I was a B
I was a Base
Provided that all the classes involved are default constructible, B
need not be a virtual base of cloner<B,D> and you can remove the virtual
keyword from struct cloner : virtual B. Otherwise, B must be a virtual base
so that a non-default constructor of B can be called by a constructor of D,
although B is not a direct base of D.
In C++11, where we have variadic templates, you can do without virtual
inheritance altogether by furnishing cloner<B,D> with an "all-purpose"
template constructor through which it can forward arbitrary constructor
arguments from D to B. Here is an illustration of that:
#include <iostream>
template<class B, class D>
struct cloner : B
{
B *clone() const override {
return new D(dynamic_cast<D const&>(*this));
}
~cloner() override {}
// "All purpose constructor"
template<typename... Args>
explicit cloner(Args... args)
: B(args...){}
};
struct Base
{
explicit Base(int i)
: _i(i){}
virtual ~Base() {
std::cout << "I was a Base storing " << _i << std::endl;
};
virtual Base* clone() const = 0;
protected:
int _i;
};
struct A : cloner<Base,A>
{
explicit A(int i)
: cloner<Base,A>(i){}
~A() override {
std::cout << "I was an A storing " << _i << std::endl;
};
};
struct B : cloner<Base,B>
{
explicit B(int i)
: cloner<Base,B>(i){}
~B() override {
std::cout << "I was a B storing " << _i << std::endl;
};
};
struct DB : cloner<B,DB>
{
explicit DB(int i)
: cloner<B,DB>(i){}
~DB() override {
std::cout << "I was a DB storing " << _i << std::endl;
};
};
int main()
{
Base * pBaseA = new A(1);
Base * pBaseB = new B(2);
Base * pBaseDB = new DB(3);
Base * pBaseCloneOfA = pBaseA->clone();
Base * pBaseCloneOfB = pBaseB->clone();
Base * pBaseCloneOfDB = pBaseDB->clone();
B * pBCloneOfDB = dynamic_cast<B*>(pBaseDB->clone());
std::cout << "deleting pA" << std::endl;
delete pBaseA;
std::cout << "deleting pB" << std::endl;
delete pBaseB;
std::cout << "deleting pDB" << std::endl;
delete pBaseDB;
std::cout << "deleting pBaseCloneOfA" << std::endl;
delete pBaseCloneOfA;
std::cout << "deleting pBaseCloneOfB" << std::endl;
delete pBaseCloneOfB;
std::cout << "deleting pBaseCloneOfDB" << std::endl;
delete pBaseCloneOfDB;
std::cout << "deleting pBCloneOfDB" << std::endl;
delete pBCloneOfDB;
return 0;
}
And the output is:
deleting pA
I was an A storing 1
I was a Base storing 1
deleting pB
I was a B storing 2
I was a Base storing 2
deleting pDB
I was a DB storing 3
I was a B storing 3
I was a Base storing 3
deleting pBaseCloneOfA
I was an A storing 1
I was a Base storing 1
deleting pBaseCloneOfB
I was a B storing 2
I was a Base storing 2
deleting pBaseCloneOfDB
I was a DB storing 3
I was a B storing 3
I was a Base storing 3
deleting pBCloneOfDB
I was a DB storing 3
I was a B storing 3
I was a Base storing 3

What you can do is to propagate the base through the whole inheritance
hierarchy, but I don't think this will be particularly useful as for
every further derived class you now get a whole new hierarchy and all
the polymorphism is going to be for naught.
#include <iostream>
class Base
{
public:
virtual ~Base() {};
virtual Base* clone() const = 0;
};
template<class Derived> class BaseCopyable : Base
{
public:
virtual Base* clone() const
{
return new Derived(static_cast<Derived const&>(*this));
}
};
struct Default;
template<typename Self, typename Arg>
struct SelfOrArg {
typedef Arg type;
};
template<typename Self>
struct SelfOrArg<Self, Default> {
typedef Self type;
};
template<typename Derived = Default>
class A : public BaseCopyable< typename SelfOrArg<A<Derived>, Derived>::type >
{
};
class derivedA : A<derivedA> {
};
Although this still has the drawback of the broken return type for
BaseCopyable. With a classic virtual constructor idiom, you get
the ability to say something like:
void func(Derived& d) {
// thanks to covariant return types Derived::clone returns a Derived*
Derived* d2 = d.clone();
delete d2;
}
This wont be possible with your scheme, although easily possible
through adjusting the return type in BaseCopyable.
Just write a macro to get rid of the boilerplate :)

Related

Copy constructing from a derived object

In the following code, the function foo is copy constructing a Base object c from a Derived object d. My question is: are we getting an exact copy? Because I'm not getting the polymorphic behavior I'm expecting
#include<iostream>
class Base
{
public:
virtual void sayHello()
{
std::cout << "Hello Base" << std::endl ;
}
};
class Derived: public Base
{
public:
void sayHello() override
{
std::cout << "Hello Derived" << std::endl ;
}
};
void foo(Base* d)
{
Base* c = new Base(*d);
c->sayHello() ;
}
int main()
{
Derived d;
foo(&d) ; //outputs Hello Base
}
There is no virtual constructor nor copy constructor.
However, it is possible to define a function that behaves like one.
In my case, it is the virtual member function copy() which I added to OP's sample:
#include <iostream>
class Base
{
public:
virtual Base* copy() const { return new Base(*this); }
virtual void sayHello()
{
std::cout << "Hello Base" << std::endl ;
}
};
class Derived: public Base
{
public:
virtual Base* copy() const override { return new Derived(*this); }
void sayHello() override
{
std::cout << "Hello Derived" << std::endl ;
}
};
void foo(Base* d)
{
Base* c = d->copy();
c->sayHello() ;
}
int main()
{
Derived d;
foo(&d) ; //outputs Hello Derived
return 0;
}
Output:
Hello Derived
Live Demo on coliru
The drawback is that every derived class of Base has to provide it to make it function properly. (I've no idea how to convince the compiler to check this for me with any trick.)
A partial solution could be to make copy() pure virtual in the class Base (assuming it is not meant to be instantiable).
you may wonna change the line of new
Base* c = new Derived(*d);
so you have the type Derived in a Base pointer. During runtime it is looked up, which type it is and you get the right output.
let me know if im wrong... just created this out of my mind on the fly.
To answer your question about whether or not this is copy constructing lets add some members. Base will have a member, m_b and Derived will inherit m_b but also have another member m_d
#include <iostream>
struct Base {
const int m_b;
Base() = delete;
Base(const int a_b) : m_b(a_b) {}
virtual void sayHello() {
std::cout << "Base " << m_b << std::endl;
}
};
struct Derived : public Base {
const int m_d;
Derived() = delete;
Derived(const int a_b, const int a_d) : Base(a_b), m_d(a_d) {}
void sayHello() override {
std::cout << "Derived " << m_b << ' ' << m_d << std::endl;
}
};
void foo(Derived* a) {
Base* b = new Base(*a);
b->sayHello(); // Output is "Base 1", 1 was copied from argument a
}
void bar(Derived* a) {
Base* d = new Derived(*a);
d->sayHello(); // Output is "Derived 1 2"
}
int main() {
Derived d(1, 2);
foo(&d);
bar(&d);
return 0;
}
The line:
Base* b = new Base(*a);
Created a Base and so sayHello calls Base's implementation which doesn't know about m_d. However this line does copy m_b from the derived class
The line:
Base* d = new Derived(*a);
Created a Derived and so sayHello calls Derived's implementation which copied both m_b and m_d
Expected polymorphic behavior will come into existence when the Base class pointer points to Derived class object. Then at run time the actual type of object pointed to by the Base class pointer will be checked and appropriate function will get called.
Base* c = new Base(*d); // <<-- case of object slicing
Here, c points to Base class object. Therefore, c->sayHello() ; is bound to call the Base::sayHello() at runtime.
are we getting an exact copy?. No since you are creating a Base object due to new Base. Due to object slicing the Base part of the *d object is passed to copy c'tor and what you get is corresponding Base object.
Base *c = new Derived(*d); will give the expected behavior.

C++ interface inheritance different arguments method

class Base
{
public:
virtual void print() = 0;
};
class A : public Base
{
int mClassA;
public:
A() : mClassA(1) {}
void print() override { std::cout << "print A" << std::endl; }
void foo( A& arg ) { std::cout << mClassA << std::endl; }
};
class B : public Base
{
int mClassB;
public:
B() : mClassB(2) {}
void print() override { std::cout << "print B" << std::endl; }
void foo( B& arg ) { std::cout << mClassB << std::endl; }
};
So I got class structure similar to this. What approach should I take to call foo without dynamic_cast each time?
int main()
{
Base * obj1 = new A();
Base * obj2 = new A();
dynamic_cast<A*>(obj1)->foo(*dynamic_cast<A*>(obj2));
}
I could create foo method with base class argument but I want to be sure that I'm passing A or B obejct as an argument.
You could use templates to make sure that a particular parameter of one of the class' member functions has at least a particular type. See the following code illustrating this:
template <class P>
class Base
{
public:
Base(int nr) : mClass(nr) {}
virtual void print() = 0;
virtual void foo( P& arg ) { std::cout << mClass << std::endl; }
protected:
int mClass;
};
class A : public Base<A>
{
public:
A() : Base(1) {}
void print() override { std::cout << "print A" << std::endl; }
virtual void foo( A& arg ) override { Base::foo(arg); cout << "is A for sure" << endl; }
};
class B : public Base<B>
{
public:
B() : Base(2) {}
void print() override { std::cout << "print A" << std::endl; }
virtual void foo( B& arg ) override { Base::foo(arg); cout << "is B for sure" << endl; }
};
int main()
{
Base<A> * obj1 = new A();
A* obj2 = new A();
obj1->foo(*obj2);
Base<B> * objb1 = new B();
B* objb2 = new B();
objb1->foo(*objb2);
// objb1->foo(*obj2);
// Non-const lvalue reference to type 'B' cannot bind to a value of unrelated type 'A'
}
It sounds like you're wanting to do something like this:
class Base
{
public:
virtual void foo(Base&) = 0;
};
class A : public Base
{
public:
void foo(A&);
};
class B : public Base
{
public:
void foo(B&);
};
In object oriented design, this is known as covariance (specifically, a "covariant method argument type").
The problem is that this goes against principles of good object oriented design. The Liskov substitution principle says that, if you have a base class Base, then any instances of subclasses of Base need to be interchangeable - but you want some subclasses of Base to not work with other subclasses of Base. (This is an oversimplification, but there are plenty of discussions online with more detail.)
If you want to do this - if it's the best solution in your case, in spite of the general advice of the Liskov substitution principle - then you can implement the checks yourself.
void A::foo(Base& base_arg) {
// This will throw a runtime exception if the wrong type
A& arg = dynamic_cast<A&>(base_arg);
std::cout << mClassA << std::endl;
}
Note that you're sacrificing some compile-time type safety now - if you accidentally try to call A::foo with an instance of B, you won't know until the code runs and you get an exception. (That's the whole point of virtual functions / dynamic dispatch / polymorphism - the behavior is determined at runtime.)
Another approach would be to use templates, like #Stephen Lechner's solution. That gives up runtime polymorphism, but it keeps strong type safety and better follows conventional OO design.
The Wikipedia article on covariance has a lot more discussion, including further example code.

Conditional call to base constructor

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);
}

Override member field in derived classes

I have a code snippet below:
#include <iostream>
using namespace std;
class Base {
public:
Base() : b(0) {}
int get();
virtual void sayhello() { cout << "Hello from Base with b: " << b << endl; }
private:
int b;
};
int Base::get() {sayhello(); return b;}
class Derived : public Base {
public:
Derived(double b_):b(b_){}
void sayhello() { cout << "Hello from Derived with b: " << b << endl; }
private:
double b;
};
int main() {
Derived d(10.0);
Base b = d;
cout << "Derived b: " << d.get() << endl;
cout << "Base b: " << b.get() << endl;
}
Run the compiled executable and I find the result is out of my expectation on my llvm-g++ 4.2 machine. The output on my box is as
Hello from Derived with b: 10
Derived b: 0
Hello from Base with b: 0
Base b: 0
What I want to do in the code is to override a member field (b) in Derived class.
Since I think both Base and Derived need to access this field, I define a get member function in Base, thus Derived can inherit it.
Then I try to get the member field from different objects.
The result shows that I still get original b in Base by d.get() instead of that in Derived, which is what I expected the code to do.
Anything wrong with the code (or my understanding)? Is this behavior specified in the specification? What is the right way to override a member field and properly define its getter and setter?
The new b added in the derived class doesn't override base's b. It just hides it.
So, in the derived class you have two b and the virtual method prints corresponding b.
You can't simply override a member field, and as Base::get is compiled, the b variable is resolved to Base::b so this method will always use this value and not a value from another field with the same name in a derived class.
The usual way to override an attribute is to override the way you access it, i.e. override the accessors (getter and setter).
You can achieve something like that by decorating the getter, but the getter return type will always be the same:
class Base {
public:
Base() : b(0) {}
int get();
virtual void sayhello() { cout << "Hello from Base with b: " << b << endl; }
protected:
virtual int getB() {return b;}
private:
int b;
};
int Base::get() {sayhello(); return getB();}
class Derived : public Base {
public:
Derived(double b_):b(b_){}
void sayhello() { cout << "Hello from Derived with b: " << b << endl; }
protected:
int getB() override {return b;} // conversion from double to int
private:
double b;
};
I'm not sure I understand you correctly, but it by "override" you mean "replace", you'd use a template:
#include <iostream>
using namespace std;
template< typename T >
class Base {
public:
Base() : b(0) {}
Base(T b_) : b(b_) {}
T get();
virtual void sayhello() { cout << "Hello from Base with b: " << b << endl; }
protected:
T b;
};
template< typename T >
T Base<T>::get() {sayhello(); return b;}
class Derived : public Base<double> {
public:
Derived(double b_):Base(b_){}
void sayhello() { cout << "Hello from Derived with b: " << this->b << endl; }
};
int main() {
Derived d(10.0);
Base<double>* b = &d;
cout << "Derived b: " << d.get() << endl;
cout << "Base b: " << b->get() << endl;
}
You code in main was also attempting Base b = d; which would lead to slicing, the above fixes that and makes sure you don't accidentially use Base<int> instead of Base<double>.
Live example
you should rewrite your Derived::ctor as follows:
Derived(double _b)
:Base(_b)
{}
And remove filed b in Derived class. Instead mark b in the Base class as protected.
EDIT
Disregard all of this
I've found a problem in your code:
Base b = d;
You're copying derived object to base. It copies only base fields. If you want polymorphism try next:
Base *b = &d;
b->get()

Polymorphism in C++ does not work correctly with reference

I have a simple code which doesn't work correctly with reference (polymorphism).
#include <iostream>
#include <string>
class Base {
public:
Base() {}
virtual ~Base() {}
virtual std::string text() const {
return "Base";
}
};
class Derived: public Base {
public:
Derived(Base& _b): b(_b) {}
virtual ~Derived() {}
virtual std::string text() const {
return b.text() + " - Derived";
}
private:
Base& b;
};
int main(int argc, char const *argv[])
{
Base b;
Derived d1(b);
std::cout << d1.text() << std::endl;
Derived d2(d1);
std::cout << d2.text() << std::endl;
return 0;
}
And output:
Base - Derived
Base - Derived
The second line in output I expected: Base - Derived - Derived. I read some resources and polymorphism work perfectly with reference and pointer but in this situation, it doesn't. If I replace reference by pointer, it work again. So, anybody can give me some explainations?
Thanks so much!
You're invoking the default copy constructor to Derived. Therefore when finished d2 will be a simple member-copy of d1, and both their b members will reference the same Base instance.
To prove this, add this to your Derived class
class Derived: public Base {
public:
Derived(Derived& d) : b(d) {}
Derived(Base& _b): b(_b) {}
virtual ~Derived() {}
virtual std::string text() const {
return b.text() + " - Derived";
}
private:
Base& b;
};
With this your output will become:
Base - Derived
Base - Derived - Derived
And just note, this is not a grand idea or a stellar learning example of polymorphism. (But it is an interesting example of construction overriding). Also note this is NOT a typical override of default copy-construction (where the parameter is a const-ref-type). Thus part of the reason this is not the greatest sample.
If you instrument the code you will see that when you call Derived d2(d1) the Derived::Derived(Base&)
constructor is not being called. This is because the d1 argument is a better match for the
implicit copy constructor, which just copies the b member from d1 to d2.
In order to see the behavior you expect, you can explicitly cast the d1 to (Base&)d1. If you do
so you will get code like the following (with the instrumentation):
#include <iostream>
#include <string>
class Base {
public:
Base() {}
virtual ~Base() {}
virtual std::string text() const {
return "Base";
}
};
class Derived: public Base {
public:
Derived(Base& _b): b(_b) {std::cout << "init'ed with: " << _b.text() << std::endl;}
virtual ~Derived() {}
virtual std::string text() const {
return b.text() + " - Derived";
}
private:
Base& b;
};
int main(int argc, char const *argv[])
{
std::cout << "Creating Base" << std::endl;
Base b;
std::cout << "Creating d1" << std::endl;
Derived d1(b);
std::cout << d1.text() << std::endl;
std::cout << "Creating d2" << std::endl;
Derived d2(d1);
std::cout << d2.text() << std::endl;
std::cout << "Creating d3" << std::endl;
Derived d3((Base&)d1);
std::cout << d3.text() << std::endl;
return 0;
}
And this gives the expected output:
Creating Base
Creating d1
init'ed with: Base
Base - Derived
Creating d2
Base - Derived
Creating d3
init'ed with: Base - Derived
Base - Derived - Derived
Your d1 and d2 both have type Derived so this is working correctly. Typically the references are reversed; e.g.
Base b;
Derived d;
Base &dr = d;
std::cout << b.text() << std::endl;
std::cout << dr.text() << std::endl;
Here text() is invoked through a Base type but the latter will call the version in Derived.
Note that it doesn't typically make sense to allow a derived class to be initialized via a base class. Suppose you add type Derived2 that has abilities or state much different from Derived. This constructor would allow
Derived2 d2;
Derived d1(d2);
which is likely a very bad idea.
As noted correctly in the comment, it is now using the default copy constructor, and that is the reason for your observation with the same output for both. So, d1 is just copied into d2 rather than used for the base member variable inside d2.