实现可克隆 c++ 类 的最佳方法?
The best way to implement cloneable c++ classes?
我已经看到了必须在 class 中实现 clone
方法的问题的解决方案(包括在本站点中),因此它 return
是堆分配的克隆本身即使我们只有 Base
class.
当你不得不在很多 class 中一次又一次地实现相同的方法时,问题就出现了,我记得当你只需要从模板继承时这样做的方法 class(将其命名为 Cloneable
)所以它实现了它,但是我尝试这样做的方式不起作用:
template<typename T, typename B> class Cloneable{
public:
B* clone(){return new T(*this);}
};
class Bottom {
public:
virtual void sayhi() = 0;
virtual Bottom* clone() = 0;
};
class Middle: public Cloneable<Middle, Bottom>, public Bottom {
public:
void sayhi() override {cout << "Hi from the Middle" << endl;}
};
//class Top: public Middle ...?
int main() {
Bottom* b1 = new Middle();
b1->sayhi();
delete b1;
}
我记得向我展示这个的人实际上在 Cloneable
中只用了一个参数就做到了,但无论如何,我会感谢你能想象到的任何方式。
您可以使用 Curious Recurring Template Pattern,其中派生的 class 实际上派生自基于 class 的实例,具体取决于自身。演示:
#include <iostream>
template<typename T>
class Clonable {
public:
T* clone() {
return new T { * static_cast<T *>(this)};
}
};
template<class T>
class Base : public Clonable<T> {
public:
int x = 2;
virtual ~Base() {}
};
class Derived : public Base<Derived> {
public:
int y = 3;
};
int main() {
Base<Derived> *d = new Derived;
static_cast<Derived *>(d)->y = 6;
Derived *c = d.clone(); // we are even cloning from a Base *!
std::cout << c->x << ' ' << c->y << '\n';
delete c;
delete d;
}
编译无警告并正确输出2 6
,证明没有发生切片。
您的 Cloneable
缺少演员表。 this
是一个 Cloneable *
,它需要转换为 T *
才能传递给复制构造函数。
template<typename T, typename B> class Cloneable : public B
{
public:
B* clone() override { return new T(*static_cast<T*>(this)); }
};
class Base
{
public:
virtual Base* clone() = 0;
};
class Derived : public Cloneable<Derived, Base>
{
};
这不会阻止某人进一步子classing Derived
,并忘记为那个孙子 class.
重新实现 clone
class Oops : public Derived {};
int main() {
Oops o;
Base * pb = o.clone();
assert(typeid(*pb) != typeid(o));
}
我已经看到了必须在 class 中实现 clone
方法的问题的解决方案(包括在本站点中),因此它 return
是堆分配的克隆本身即使我们只有 Base
class.
当你不得不在很多 class 中一次又一次地实现相同的方法时,问题就出现了,我记得当你只需要从模板继承时这样做的方法 class(将其命名为 Cloneable
)所以它实现了它,但是我尝试这样做的方式不起作用:
template<typename T, typename B> class Cloneable{
public:
B* clone(){return new T(*this);}
};
class Bottom {
public:
virtual void sayhi() = 0;
virtual Bottom* clone() = 0;
};
class Middle: public Cloneable<Middle, Bottom>, public Bottom {
public:
void sayhi() override {cout << "Hi from the Middle" << endl;}
};
//class Top: public Middle ...?
int main() {
Bottom* b1 = new Middle();
b1->sayhi();
delete b1;
}
我记得向我展示这个的人实际上在 Cloneable
中只用了一个参数就做到了,但无论如何,我会感谢你能想象到的任何方式。
您可以使用 Curious Recurring Template Pattern,其中派生的 class 实际上派生自基于 class 的实例,具体取决于自身。演示:
#include <iostream>
template<typename T>
class Clonable {
public:
T* clone() {
return new T { * static_cast<T *>(this)};
}
};
template<class T>
class Base : public Clonable<T> {
public:
int x = 2;
virtual ~Base() {}
};
class Derived : public Base<Derived> {
public:
int y = 3;
};
int main() {
Base<Derived> *d = new Derived;
static_cast<Derived *>(d)->y = 6;
Derived *c = d.clone(); // we are even cloning from a Base *!
std::cout << c->x << ' ' << c->y << '\n';
delete c;
delete d;
}
编译无警告并正确输出2 6
,证明没有发生切片。
您的 Cloneable
缺少演员表。 this
是一个 Cloneable *
,它需要转换为 T *
才能传递给复制构造函数。
template<typename T, typename B> class Cloneable : public B
{
public:
B* clone() override { return new T(*static_cast<T*>(this)); }
};
class Base
{
public:
virtual Base* clone() = 0;
};
class Derived : public Cloneable<Derived, Base>
{
};
这不会阻止某人进一步子classing Derived
,并忘记为那个孙子 class.
clone
class Oops : public Derived {};
int main() {
Oops o;
Base * pb = o.clone();
assert(typeid(*pb) != typeid(o));
}