Consider the following scenario:
class AbsBase {
public:
virtual double foo() = 0;
};
class Concrete1 : public AbsBase {
public:
double foo() {
return 1;
}
};
class Concrete2 : public AbsBase {
public:
double foo() {
return 2;
}
};
struct Config {
/**
* Must use a pointer to `AbsBase`, since it is an abstract base class,
* and the concrete instances could be of either of the derived classes.
*/
AbsBase* thing;
void setThing(AbsBase* t) {
thing = t;
}
};
This works, but I would prefer it if thing
were a copy of the argument passed to setThing
. I.e. if thing
were of type Concrete1
(as opposed to an abstract base class) I could do something like this:
Concrete1 thing;
void setThing(const Concrete1& t) {
thing = Concrete1(t);
}
However I can't see a way of achieving this without instantiating an object of an abstract type (which is illegal). Any ideas?
You can use a template function to achieve the wanted behavior.
I would recommend to also use std::unique_ptr
to prevent memory issues.
class AbsBase {
public:
virtual ~AbsBase() = default;
virtual double foo() = 0;
};
class Concrete1 : public AbsBase {
public:
double foo() {
return 1;
}
};
class Concrete2 : public AbsBase {
public:
double foo() {
return 2;
}
};
struct Config {
/**
* Must use a pointer to `AbsBase`, since it is an abstract base class,
* and the concrete instances could be of either of the derived classes.
*/
std::unique_ptr<AbsBase> thing;
template <typename T>
void setThing(const T& t) {
static_assert(std::is_base_of<AbsBase, T>::value, "T must inherit AbsBase");
static_assert(std::is_copy_constructible<T>::value, "T must be copy-constructible");
thing.reset(new T{t});
}
void test()
{
std::cout << (thing?thing->foo():0.0) << std::endl;
}
};