C++ 通过调用 base class 优雅地克隆派生 class
C++ elegantly clone derived class by calling base class
我需要克隆一个派生的 class,只给出一个指向基 class 的引用或指针。下面的代码完成了这项工作,但看起来并不优雅,因为我将样板代码放入许多派生的 classes C、D、E 中,它们是 B(未显示)的兄弟,仅调用默认副本每个的构造函数。如果它可以是虚拟的,这不是默认复制构造函数的用途吗?
有没有更好的方法?
创建虚拟赋值运算符是错误的,因为我不想让 C 赋值给 B、B 给 D 等,只需克隆 B、C、D 或 E。
#include <iostream>
using namespace std;
class A {
public:
virtual ~A() {}
virtual A* clone()=0;
};
class B : public A {
int i;
public:
virtual A* clone() {
cout << "cloned B" << endl;
return new B(*this);
}
virtual ~B() { cout << "destroyed b" << endl; }
};
int main() {
A* a = new B();
A* aa = a->clone();
delete a;
delete aa;
return 0;
}
您始终可以将所有克隆逻辑粘贴到层次结构中间的自己的 class 中:
template <class Derived, class Base>
class CloneCRTP : public Base {
public:
Derived* clone() const override {
return new Derived(static_cast<Derived const&>(*this));
}
};
然后:
class B : public CloneCRTP<B, A>
{
int i;
public:
virtual ~B() { cout << "destroyed b" << endl; }
};
不再有样板文件。
您可以依赖 CRTP 惯用法。
它遵循一个最小的工作示例:
struct B {
~virtual ~B() { }
virtual B* clone() = 0;
};
template<class C>
struct D: public B {
B* clone() {
return new C{*static_cast<C*>(this)};
}
};
struct S: public D<S> { };
int main() {
B *b1 = new S;
B *b2 = b1->clone();
delete b1;
delete b2;
}
要实现与协变 return 类型一起工作的克隆,需要一些更复杂的 CRTP:
class Shape {
// virtual
virtual Shape* do_clone() const = 0;
public:
virtual ~Shape() {}
// non-virtual
Shape* clone() const {
return do_clone();
}
// ...
};
template <class Derived, class Base>
class CloneCRTP : public Base {
// virtual
Shape* do_clone() const override {
return new Derived(static_cast<Derived const&>(*this));
}
public:
// non-virtual
Derived* clone() const {
return static_cast<Derived*>(do_clone());
}
};
用法:
class Rectangle: public CloneCRTP<Rectangle, Shape> { /*...*/ };
class Triangle: public CloneCRTP<Triangle, Shape> { /*...*/ };
int main() {
Rectangle* r1 = new Rectangle{};
// getting the proper type from clone:
Rectangle* rcopy = r1->clone();
delete rcopy;
delete r1;
Triangle t1{};
// getting the proper type from clone:
Triangle* tcopy = t1.clone();
delete tcopy;
}
我需要克隆一个派生的 class,只给出一个指向基 class 的引用或指针。下面的代码完成了这项工作,但看起来并不优雅,因为我将样板代码放入许多派生的 classes C、D、E 中,它们是 B(未显示)的兄弟,仅调用默认副本每个的构造函数。如果它可以是虚拟的,这不是默认复制构造函数的用途吗?
有没有更好的方法?
创建虚拟赋值运算符是错误的,因为我不想让 C 赋值给 B、B 给 D 等,只需克隆 B、C、D 或 E。
#include <iostream>
using namespace std;
class A {
public:
virtual ~A() {}
virtual A* clone()=0;
};
class B : public A {
int i;
public:
virtual A* clone() {
cout << "cloned B" << endl;
return new B(*this);
}
virtual ~B() { cout << "destroyed b" << endl; }
};
int main() {
A* a = new B();
A* aa = a->clone();
delete a;
delete aa;
return 0;
}
您始终可以将所有克隆逻辑粘贴到层次结构中间的自己的 class 中:
template <class Derived, class Base>
class CloneCRTP : public Base {
public:
Derived* clone() const override {
return new Derived(static_cast<Derived const&>(*this));
}
};
然后:
class B : public CloneCRTP<B, A>
{
int i;
public:
virtual ~B() { cout << "destroyed b" << endl; }
};
不再有样板文件。
您可以依赖 CRTP 惯用法。
它遵循一个最小的工作示例:
struct B {
~virtual ~B() { }
virtual B* clone() = 0;
};
template<class C>
struct D: public B {
B* clone() {
return new C{*static_cast<C*>(this)};
}
};
struct S: public D<S> { };
int main() {
B *b1 = new S;
B *b2 = b1->clone();
delete b1;
delete b2;
}
要实现与协变 return 类型一起工作的克隆,需要一些更复杂的 CRTP:
class Shape {
// virtual
virtual Shape* do_clone() const = 0;
public:
virtual ~Shape() {}
// non-virtual
Shape* clone() const {
return do_clone();
}
// ...
};
template <class Derived, class Base>
class CloneCRTP : public Base {
// virtual
Shape* do_clone() const override {
return new Derived(static_cast<Derived const&>(*this));
}
public:
// non-virtual
Derived* clone() const {
return static_cast<Derived*>(do_clone());
}
};
用法:
class Rectangle: public CloneCRTP<Rectangle, Shape> { /*...*/ };
class Triangle: public CloneCRTP<Triangle, Shape> { /*...*/ };
int main() {
Rectangle* r1 = new Rectangle{};
// getting the proper type from clone:
Rectangle* rcopy = r1->clone();
delete rcopy;
delete r1;
Triangle t1{};
// getting the proper type from clone:
Triangle* tcopy = t1.clone();
delete tcopy;
}