1. В Си++ нет такого понятия, как виртуальный конструктор. А виртуальный конструктор копирования — я вообще не понимаю…
2. В makecopy вы допустили ошибку — переменная никуда не девается и тупо занимает память.
3. Чтобы отдать указатель на переменную и сказать: «сам уничтожай, когда хочешь»,— есть стандартный тип unique_ptr. Но для ковариантности по unique_ptr нужны две функции: одна виртуальная и возвращает простой указатель, другая отдаёт конкретный u_p.
Для простоты предполагаю, что все классы неабстрактные, и виртуальная vclone имеет права доступа public, а не protected.
#include <iostream>
#include <memory>
#define IMPLEMENT_CLONE_1(Class, Keyword) \
virtual Class* vclone() const Keyword { return new Class(*this); } \
auto clone() const { return std::unique_ptr<Class>{vclone()}; }
#define IMPLEMENT_CLONE(Class) IMPLEMENT_CLONE_1(Class, override)
class BaseClass {
public:
IMPLEMENT_CLONE_1(BaseClass, )
virtual ~BaseClass() = default;
};
class MyClass : public BaseClass {
public:
IMPLEMENT_CLONE(MyClass)
void print() const { std::cout << "I'm a MyClass!" << std::endl; }
};
int main()
{
auto a = std::make_unique<MyClass>();
auto b = a->clone();
b->print();
return 0;
}
Есть ещё
вот такая хрѣнь. Я уж не знаю, что лучше:
сóрок пя́ток или пятóк сорóк прямое преобразование указателей или препроцессор.
#include <iostream>
#include <memory>
class BaseClass {
public:
auto clone() const { return std::unique_ptr<BaseClass>{ vclone() }; }
protected:
virtual BaseClass* vclone() const { return new BaseClass(*this); }
};
template <class Super, class This>
class CloneImpl : public Super
{
public:
auto clone() const { return std::unique_ptr<This>{ static_cast<This*>(vclone()) }; }
protected:
CloneImpl* vclone() const override { return new This(*static_cast<const This*>(this)); }
};
class MyClass : public CloneImpl<BaseClass, MyClass> {
public:
void print() const { std::cout << "I'm a MyClass!" << std::endl; }
};
int main()
{
auto a = std::make_unique<MyClass>();
auto b = a->clone();
b->print();
return 0;
}