Prevent writing clone method for each subclass - c++

Here is my case:
class A
{
public:
virtual A* clone() = 0;
};
class B : public A
{
virtual B* clone() override
{
return new B();
}
};
In my code now 100% of sublcasses of A just implement the clone method exactly the same way only for class D I have return type D and I create object of D of course.
How can I prevent this duplication? What patterns or tricks can help?
I have thought to use CRTP pattern, but it uses templates, and my function is virtual. As we understand templates and virtual functions are incompatible.
NVI pattern does not work either, as return type of clone methods are different.

[class.virtual]/8:
If the class type in the covariant return type of D::f differs from
that of B::f, the class type in the return type of D::f shall be
complete at the point of declaration of D::f or shall be the class
type D.
So CRTP cannot work perfectly, since the template argument which refers to the derived class would be an incomplete type, and thus covariant return types are difficult to simulate.
However, here's a try:
class A
{
public:
virtual A* clone() = 0;
};
namespace detail {
template <typename T>
struct Cloner : A {
using A::A; // For constructors
virtual A* clone() override {return new T;}
};
}
template <typename T>
struct Cloner : detail::Cloner<T> {
using detail::Cloner<T>::Cloner; // For constructors
// For callers
template <class=void>
T* clone() {return static_cast<T*>(detail::Cloner<T>::clone());}
};
class B : public Cloner<B>
{
};
Demo.
Note two things:
The overload of clone returning a pointer to the derived class type is a function template. That's so we don't override the virtual function clone: If we would, the code would be ill-formed, because the return type is not covariant (see above).
Because clone is a function template, to ensure that it get's called at all, we can to let it hide the virtual clone function. That's achieved via inheritance: Names in derived classes hide names in base classes. Thus if we call through a B-pointer/reference, we get the appropriate return type (B*), since the name is looked up in ::Cloner before detail::Cloner.

Related

Invalid covariant return type for ... override [duplicate]

I'm trying to implement a Clonable class with the CRTP. However, I need to have abstract class that have a pure virtual clone method, overridden by child classes. To make this happen, I need the clone function to return a covariant return type. I made this code below, and the compiler shout at me this error:
main.cpp:12:5: error: return type of virtual function 'clone' is not covariant with the return type of the function it overrides ('B *' is not derived from 'AbstractClonable *')
The class 'B' seems to be a child class of AbstractClonable, and even by two way! How can I solve this? Thank you very much. I tried with both with clang 3.6 and GCC 4.9.2
struct AbstractClonable {
virtual AbstractClonable* clone() const = 0;
};
template<typename T>
struct Clonable : virtual AbstractClonable {
T* clone() const override {
return new T{*dynamic_cast<const T*>(this)};
}
};
struct A : virtual AbstractClonable {
};
struct B : A, Clonable<B> {
};
Even if B is indeed derived from Clonable<B>, the problem here is that Clonable<B> construction is not valid, as it defines
B* clone() const override
which of course is not an override of AbstractClonable::clone(), since the compiler doesn't see B at this point as a child of AbstractClonable. So I believe the issue lays in the fact that the compiler cannot build the Clonable<B> base of B.
A workaround (but not really the same as what you want) is to define
Clonable* clone() const override
in Clonable. As you mentioned in the comment, you can also define a free function
template<typename T>
T* clone(const T* object)
{
return static_cast<T*>(object->clone());
}
Related: Derived curiously recurring templates and covariance
Yes, B is derived from AbstractClonable, but the compiler doesn't know that during the instantiation of Clonable<B> because B is still incomplete at that point.
C++14 §10.3/8:
If the class type in the covariant return type of D::f differs from that of B::f, the class type in the return type of D::f shall be complete at the point of declaration of D::f or shall be the class type D.
A class has special permission to use itself in a covariant return type. Other classes, including CRTP bases, need to wait until the class is complete before declaring a covariant function.
You can solve the problem using the non-virtual interface idiom (NVI):
class AbstractClonable {
protected:
virtual AbstractClonable* do_clone() const = 0;
public:
AbstractClonable *clone() const {
return do_clone();
}
};
template<typename T>
class Clonable : public virtual AbstractClonable {
Clonable* do_clone() const override { // Avoid using T in this declaration.
return new T{*dynamic_cast<const T*>(this)};
}
public:
T *clone() const { // But here, it's OK.
return static_cast< T * >( do_clone() );
}
};
I think the problem is that
T* clone() const override{
return new T{*dynamic_cast<const T*>(this)};
}
returns B* instead of AbstractClonable *.

Defining variadic function specialization in child class

I am trying to allow a child class to define the variadic function specialization. For example:
#include <iostream>
#include <vector>
#include <memory>
class BaseClass
{
public:
BaseClass() {};
virtual ~BaseClass() {};
template<typename GenericData>
void ReceiveData(GenericData &inData)
{
throw std::runtime_error("Undefined");
}
};
class ReceiveInt : public BaseClass
{
void ReceiveData(int & inData)
{
std::cout << "I know what to do!";
}
};
int main(int argc, char* argv[])
{
std::vector<std::shared_ptr<BaseClass>> classHolder;
classHolder.push_back(std::make_shared<ReceiveInt>());
int test = 1;
classHolder.front()->ReceiveData(test);
return 0;
}
But unfortunately this does not work, as the BaseClass ReceiveData function is called. Is this even possible?
EDIT 1
As people have pointed out, I'm very wrong with my notation. Looks like I learned more than I expected today.
Is this even possible?
I don't think so.
Dynamic dispatch is possible only for virtual member functions.
Member function templates may not be virtual.
If you can use regular member functions, i.e. not member function templates, then you can make them virtual. That will work.
You confuse some notions here.
To start with, there are no variadic templates here as ReceiveData function below:
template<typename GenericData>
void ReceiveData(GenericData &inData)
{
throw std::runtime_error("Undefined");
}
is a template member function.
Then, if you want to override a method in the derived class, the right way is to use virtual functions, probably a pure virtual function in the base class and a virtual function with an override specifier in the derived class.
However, virtual functions limit you to a a set of fixed types because there are no template virtual functions. You could experiment with CRTP though:
template<typename T>
class Base {
public:
void receiveData(const T&) {}
};
class ReceiveInt : public Base<int> {};
which emulates a sort of static polymorphism. Below:
ReceiveInt{}.receiveData(int{});
receiveData from the base class instantiated with int.
I think you may be confusing your terminology. BaseClass::ReceiveData is a templated method, taking a template parameter GenericData. A variadic function takes a number of arguments determined at runtime.
In ReceiveInt, you're not making a specialization of anything, because ReceiveInt::ReceiveData is not a templated method. In fact, even if it was templated, it would not be possible to call in your example. How would a pointer to BaseClass know how to call a template specialization in the derived class it points to?
You can make BaseClass::ReceiveData virtual. This allows you to override it in a base class, and still call it with a pointer to BaseClass. Unfortunately, templates are a compile time language feature, whereas dynamic dispatch is a runtime feature -- in this context, you can't have both.
References
Variadic Functions
Template Specialization
Why do we need virtual functions in C++?
You would have to cast to the derived type first, it is not possible using a base class pointer/reference as the base class will only know about its own implementation. This is not even a case where you can use a recursive dependency on the derived type as the derived type is not defined yet at the point the base is being instantiated.
If you do cast to the derived type then it would be able to resolve the derived member as you desire.
There is no variadic templates in your code like already explained by the others.
But you can use the fact that the templated class methods are instantiated at the first time invoked. But there is no virtual overriding here.
In this example you can define the different implementations of the method templates in Base and Derived classes, but you have explicitely tell the compiler which one to use.
It's not possible to use Derived class method through a Base class pointer without explicit cast:
#include <iostream>
#include <memory>
using namespace std;
class Base
{
public:
Base() {};
virtual ~Base() {};
template<typename T>
void ReceiveData(T)
{
throw std::runtime_error("Undefined");
}
};
class Derived : public Base
{
public:
template<typename... Args >
void ReceiveData(Args... args)
{
(void)std::initializer_list<int>{(std::cout << args << std::endl, 0)...};
}
};
int main()
{
Base b;
// b.ReceiveData(1); //-> this calls base class method
Derived d;
d.ReceiveData(1); // this calls the method in the derived class
d.ReceiveData(2, "hello"); // this calls the method in the derived class
Base* b2 = new Derived();
// b2->ReceiveData(3); // this will instantiate and call the base class method
// thus raising an exception
// because no virtual overriding of templated methods
((Derived*)b2)->ReceiveData("world",1); // this will instantiate and call the derived class
// method, then because of explicit casting the
// compiler knows which class to target
return 0;
}
Live demo: https://wandbox.org/permlink/K0qEAC7C7yzg6gYL

How to inherit abstract behavior from c++ base class

Suppose I want to implement abstract behavior in a base class that is inherited by all derived classes. For example, a function that clones an object, applies some modification to it and returns the cloned and modified object (e.g. transposition, duplication, etc). The following code uses an even simpler function that merely returns the object itself:
class Base
{
public:
virtual Base* yourself ()
{
return this;
}
};
class Derived : public Base
{
public:
...
};
void main()
{
Derived d;
auto result = d.yourself();
}
If I didn't miss something, result will be of type Base*, where the intention clearly is to get an object of type Derived*.
Is there a way to have yourself() return the intended value for all derived classes without overriding it in all places (actually the whole point of inheritance is to implement each behavior only once)?
This issue is fairly common, and you can get around it using templates. Something like this:
template <class T>
class Base
{
public:
virtual T* yourself ()
{
return dynamic_cast<T*>(this);
}
};
class Derived : public Base<Derived>
{
public:
...
};
It's called the Curiously recurring template pattern (CRTP)

Abstract base class using template argument from derived class

I have a base class which provides pure virtual interfaces. I need this to store pointers to derived-class objects in a list of pointers to the base class.
The derived class is created using the template mechanism. The problem is now that if I want to have a virtual interface to return a type which is known only to the derived class, I need to pass it as a template argument as well. This is where the dilemma starts...
template <typename ITEM>
class base {
public:
virtual ITEM* get() = 0;
};
template <typename ITEM>
class derived : public base<ITEM>{
public:
ITEM* get() {...};
};
But when using a template in base I need to know this even when creating a list of base pointers:
base* myList[10] = {derived1, derived2,...}
Of course I don't know that type when I define my list. So I need to get rid of the template in my base class somehow.
EDIT: Got rid of this approach because it wasn't a useful approach at all. So no solution for this issue.
The code you write is not valid; there is not a single base type that is then parameterised like in Java, but a number of base<T> types. There is a way to obtain a wrapper for a truly generic object, and it is called "type erasure". It is used, for example in the implementation of boost::any.
Basically, you have a non-template base class with virtual functions, and then you make a template derived class that implements them. Note that the simplified version shown here does not work if you want to have an array of base objects, because base has pure virtual functions and thus cannot be instantiated (and because the T member of the derived type would be sliced off).
struct base;
template<typename T>
struct derived;
struct base {
virtual ~base();
// In this class we don't know about T, so we cannot use it
// Other operations that delegate to the derived class are possible, though
virtual std::size_t sizeofT() const = 0;
virtual const std::type_info& typeofT() const = 0;
// Since all you want is a pointer in "get", you could write it as a void*
virtual void* getPtr() = 0;
// Otherwise, we can implement this template function here that calls the virtual.
// Note that function templates cannot be virtual!
template<typename U>
U& getAs() {
// Verify that the type is the _same_ (no up/downcasts allowed)
// std::bad_cast is thrown here if U is not the same T used to build this object
derived<U>& meAsU = dynamic_cast<derived<U>&>(*this);
return meAsU.obj;
}
};
template<typename T>
struct derived : public base {
T obj;
// A couple of ctors to initialize the object, and the default copy/move ctors/op=
virtual ~derived();
derived(const T& o) : obj(o) {}
derived(T&& o) : obj(std::move(o)) {}
std::size_t sizeofT() const override {
return sizeof(T);
}
const std::type_info& typeofT() const override {
return typeid(T);
}
void* getPtr() override {
return static_cast<void*>(&obj);
}
};
If you want to use the base type directly as a variable, or in an array or container (vector, list, etc.), you need dynamic allocation - there are no two ways around it. You have two choices, which differ on where to place the responsibility for the dynamic allocation:
You can use the solution above if you limit yourself to having arrays of pointers to base. E.g. an array of std::unique_ptr<base>. The pointed-to objects would be of type derived<something>.
base err1; // Error, abstract class (what would it contain?)
base err2 = derived<int>(2); // Still abstract class, and the int would be sliced off
std::unique_ptr<base> ok(new derived<int>(3)); // Works
std::vector<std::unique_ptr<base>> objects;
objects.push_back(std::make_unique(new derived<int>(5)));
objects.push_back(std::make_unique(new derived<std::string>(2)));
int& a = objects[0].getAs<int>(); // works
std::string& b = objects[1].getAs<std::string>(); // works too
std::string& bad = objects[1].getAs<double>(); // exception thrown
Otherwise, you would have to implement the dynamic allocation in the base/derived classes themselves. This is what classes like boost::any or std::function do. The simplest any object would simply be a wrapper of an unique-ptr of the base class I showed here, with appropriate implementations of operators, etc. Then, you can have a variable of type any x = y; and the class would, inside its constructor, do the required new derived<Y>(y) required.

Invalid covariant type with CRTP clonable class

I'm trying to implement a Clonable class with the CRTP. However, I need to have abstract class that have a pure virtual clone method, overridden by child classes. To make this happen, I need the clone function to return a covariant return type. I made this code below, and the compiler shout at me this error:
main.cpp:12:5: error: return type of virtual function 'clone' is not covariant with the return type of the function it overrides ('B *' is not derived from 'AbstractClonable *')
The class 'B' seems to be a child class of AbstractClonable, and even by two way! How can I solve this? Thank you very much. I tried with both with clang 3.6 and GCC 4.9.2
struct AbstractClonable {
virtual AbstractClonable* clone() const = 0;
};
template<typename T>
struct Clonable : virtual AbstractClonable {
T* clone() const override {
return new T{*dynamic_cast<const T*>(this)};
}
};
struct A : virtual AbstractClonable {
};
struct B : A, Clonable<B> {
};
Even if B is indeed derived from Clonable<B>, the problem here is that Clonable<B> construction is not valid, as it defines
B* clone() const override
which of course is not an override of AbstractClonable::clone(), since the compiler doesn't see B at this point as a child of AbstractClonable. So I believe the issue lays in the fact that the compiler cannot build the Clonable<B> base of B.
A workaround (but not really the same as what you want) is to define
Clonable* clone() const override
in Clonable. As you mentioned in the comment, you can also define a free function
template<typename T>
T* clone(const T* object)
{
return static_cast<T*>(object->clone());
}
Related: Derived curiously recurring templates and covariance
Yes, B is derived from AbstractClonable, but the compiler doesn't know that during the instantiation of Clonable<B> because B is still incomplete at that point.
C++14 §10.3/8:
If the class type in the covariant return type of D::f differs from that of B::f, the class type in the return type of D::f shall be complete at the point of declaration of D::f or shall be the class type D.
A class has special permission to use itself in a covariant return type. Other classes, including CRTP bases, need to wait until the class is complete before declaring a covariant function.
You can solve the problem using the non-virtual interface idiom (NVI):
class AbstractClonable {
protected:
virtual AbstractClonable* do_clone() const = 0;
public:
AbstractClonable *clone() const {
return do_clone();
}
};
template<typename T>
class Clonable : public virtual AbstractClonable {
Clonable* do_clone() const override { // Avoid using T in this declaration.
return new T{*dynamic_cast<const T*>(this)};
}
public:
T *clone() const { // But here, it's OK.
return static_cast< T * >( do_clone() );
}
};
I think the problem is that
T* clone() const override{
return new T{*dynamic_cast<const T*>(this)};
}
returns B* instead of AbstractClonable *.