Недавно я копался в использовании CRTP для клонирования объектов с использованием ковариации в c ++ 11 и обнаружил следующее: https://www.fluentcpp.com/2017/09/12/how-to-return-a-smart-pointer-and-use-covariance/ Пост понятен, и он работает, в некотором роде.В посте не говорится о том, как использовать параметры в конструкторах.Я получил виртуальный трюк с использованием Base :: Base, хотя он заставляет пользователя явно вызывать конструкторы базы при создании экземпляра класса листа.Это требуется, только если вы ищете что-то вроде алмазного наследования.
Хотя в более обычных случаях, когда у вас есть несколько уровней наследования, у вас есть что-то вроде этого: abstract A -> abstract B ->абстрактный C -> конкретный D. Я понимаю, почему только листовой класс должен быть инстанцируемым.Но на каждом уровне конструкторы становятся все более и более конкретными, и с приведенным мною примером разработки CRTP я не понимаю, как это сделать.
В дальнейшем то, что я придумал, это упрощение:один базовый класс:
// Virtual and abstract tricks
template <typename Base>
class Virtual : virtual public Base
{
public:
using Base::Base;
};
template <typename Object>
class Abstract
{
};
// General CRTP : Inheritance + implementation of clone function
template <typename Object, typename Base=void>
class Clone : public Base
{
public:
virtual ~Clone() =default;
std::unique_ptr<Object> clone() const {
return std::unique_ptr<Object>(static_cast<Object *>(this->copy()));
}
private:
virtual Clone * copy() const override {
return new Object(static_cast<const Object &>(*this));
}
};
// Specialization : Inheritance + an pure cloning function
template <typename Object>
class Clone<Abstract<Object>>
{
public:
virtual ~Clone() =default;
std::unique_ptr<Object> clone() const {
return std::unique_ptr<Object>(static_cast<Object *>(this->copy()));
}
private:
virtual Clone *copy() const =0;
};
И в отношении моих тестовых классов:
class TestB0 : public Clone<Abstract<TestB0>>
{
public:
TestB0() : B0(new int(0)) {cout<<"crea B0 vide"<<endl;}
TestB0(int xB0) : B0(new int(xB0)) {cout<<"crea B0 "<<xB0<<" : "<<*B0<<endl;}
TestB0(const TestB0 &t) : B0(new int(*t.B0)) {cout<<"copy B0 "<<*B0<<endl;}
virtual ~TestB0() {delete B0;}
void setB0(int xB0) {*B0=xB0;}
int getB0() {return *B0;}
private:
int *B0;
};
class TestB1 : public Clone<TestB1, TestB0>
{
public:
TestB1() : B1(new int(0)) {cout<<"crea B1 vide"<<endl;}
TestB1(int xB0=11, int xB1=20) : B1(new int(xB1)) {cout<<"crea B1 "<<xB0<<" "<<xB1<<" : "<<getB0()<<" "<<*B1<<endl;}
TestB1(const TestB1 &t) : B1(new int(*t.B1)) {cout<<"copy B1 "<<getB0()<<" "<<*B1<<endl;}
virtual ~TestB1() {delete B1;}
void setB1(int xB1) {*B1=xB1;}
int getB1() {return *B1;}
private:
int *B1;
};
Когда я создаю экземпляр TestB1, у меня нет доступа к конструктору TestB0.Для этого я могу использовать виртуальный трюк:
class TestB1 : public Clone<TestB1, Virtual<TestB0>>
Но когда я это сделаю, я должен явно вызвать конструктор в листовом классе.Это не проблема, когда у меня только один уровень наследования.Я думаю, что когда у меня есть больше.
Я не могу найти способ заставить все это работать элегантно.Есть ли способ инициализировать базовый класс без использования виртуальной базы?Как обычно, когда CRTP не используется.
Спасибо за ваши ответы.
В качестве комментария: я создаю полиморфные классы для библиотеки, из которой я хочу оптимизироваться.точка зрения времени исполнения (без виртуальных таблиц).Я могу работать только с C ++ 11, поэтому использование объявления с расширением пакета не будет работать, как в C ++ 17.