.dup()
method (or .clone()
method) that returns a pointer to a copy of the (derived) object. When you have a large amount of different derived classes, overriding the base class's .dup()
method for each of them can be a bit of a nuisance. In order to solve this, I sometimes use an "intermediate" class template that can be inherited instead of the base class to provide the .dup()
method. This solution is not perfect, because it does not provide the possibility of covariant return types.
The class template
Cloneable
is defined as follows:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef CLONEABLE_HPP_ | |
#define CLONEABLE_HPP_ | |
/* a class template that can be inherited by a Derived class | |
* in stead of the Base class, such that the Derived class | |
* automatically implements the correct dup() method | |
*/ | |
template<class Base, class Derived> | |
class Cloneable : public Base { | |
public: | |
virtual ~Cloneable() { /* empty */ } | |
virtual Base* dup() const override { | |
return new Derived(*static_cast<const Derived*>(this)); | |
} | |
}; | |
#endif |
In the following code snippet, the use of the
Cloneable
is demonstrated:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Example demonstrating the Cloneable class template, | |
* which is defined in cloneable.hpp | |
* compile this file with e.g.: | |
* g++ --std=c++11 example.cpp -o example | |
*/ | |
#include <iostream> | |
#include <list> | |
#include <cmath> | |
#include "cloneable.hpp" | |
// an abstract base class for a binary operation | |
class BinaryOp { | |
public: | |
virtual ~BinaryOp() { /* empty */ } | |
// a binary operation implements operator() taking 2 arguments | |
virtual double operator()(double x, double y) const = 0; | |
// the base class MUST declare the dup() method | |
virtual BinaryOp* dup() const = 0; | |
}; | |
// some binary operations that (indirectly) inherit BinaryOp | |
class Sum : public Cloneable<BinaryOp, Sum> { | |
public: | |
double operator()(double x, double y) const override { | |
return x + y; | |
} | |
}; | |
class Product : public Cloneable<BinaryOp, Product> { | |
public: | |
double operator()(double x, double y) const override { | |
return x * y; | |
} | |
}; | |
class Hypotenuse : public Cloneable<BinaryOp, Hypotenuse> { | |
public: | |
double operator()(double x, double y) const override { | |
return sqrt(x*x + y*y); // or use the hypot function from <cmath> | |
} | |
}; | |
int main() { | |
// make a list with 3 binary operations | |
std::list<BinaryOp*> ops = {new Sum, new Product, new Hypotenuse}; | |
// define some arbitrary x and y | |
double x = 3; double y = 4; | |
// evaluate the binary operations | |
for ( auto op : ops ) { | |
std::cout << (*op)(x, y) << std::endl; | |
} | |
// make a copy of the obs list using the dup method | |
std::list<BinaryOp*> ops_copy; | |
for ( auto op : ops ) { | |
ops_copy.push_back(op->dup()); | |
} | |
// evaluate the copied operations | |
for ( auto op : ops_copy ) { | |
std::cout << (*op)(x, y) << std::endl; | |
} | |
// clean up memory | |
for ( auto op : ops ) delete op; | |
for ( auto op : ops_copy ) delete op; | |
return 0; | |
} |
No comments:
Post a Comment