奇怪重复的模板模式多态拷贝(C++)中的继承
Inheritance in curiously recurring template pattern polymorphic copy (C++)
我正在使用CRTP向继承的类添加一个克隆方法,例如:
class Base
{
virtual ~Base() {};
virtual Base* clone() const = 0;
};
template<class Derived> class BaseCopyable : Base
{
public:
virtual Base* clone() const
{
return new Derived(static_cast<Derived const&>(*this));
}
};
class A : public BaseCopyable<A>;
class B : public BaseCopyable<B>;
etc...
但是,如果我有一个从B继承的类,例如:
class differentB : public B;
那么clone()不会返回differentB类型的对象,而是返回一个B。除了在different B中编写一个新的clone(()方法外,有什么方法可以解决这个问题吗?
感谢阅读!
这是我对这个问题的回答的一个返工
您的意图是在层次结构中拥有所有派生类从基类so继承可克隆性(多态拷贝)您不需要同时为它们中的每一个提供覆盖的clone()
,但您尝试使用类模板的CRTP解决方案BaseCopyable
只能以这种方式赋予直接从Base
派生的类,而不是在派生的类上来自这样的派生类。
我认为不可能直接在通过在最高级的混凝土类。你必须明确地授予每个人具体类,但可以通过它们的基类和在不重复覆盖clone()
的情况下,通过使用CRTP将中父类的可克隆性传递给子类的模板等级制度
显然,符合该法案的CRTP模板与BaseCopyable
不同通过需要两个模板参数:父类型和子类型。
C++03解决方案如以下程序所示:
#include <iostream>
// As base of D, this makes D inherit B and makes D cloneable to
// a polymorphic pointer to B
template<class B, class D>
struct cloner : virtual B
{
virtual B *clone() const {
return new D(dynamic_cast<D const&>(*this));
}
virtual ~cloner() {}
};
struct Base
{
virtual ~Base() {
std::cout << "I was a Base" << std::endl;
};
virtual Base* clone() const = 0;
};
struct A : cloner<Base,A> // A inherits Base
{
virtual ~A() {
std::cout << "I was an A" << std::endl;
};
};
struct B : cloner<Base,B> // B inherits Base
{
virtual ~B() {
std::cout << "I was a B" << std::endl;
};
};
struct DB : cloner<B,DB> // DB inherits B, Base
{
virtual ~DB() {
std::cout << "I was a DB" << std::endl;
};
};
int main()
{
Base * pBaseA = new A;
Base * pBaseB = new B;
Base * pBaseDB = new DB;
Base * pBaseCloneOfA = pBaseA->clone();
Base * pBaseCloneOfB = pBaseB->clone();
Base *pBaseCloneOfDB = pBaseDB->clone();
B * pBCloneOfDB = dynamic_cast<B*>(pBaseDB->clone());
std::cout << "deleting pBaseA" << std::endl;
delete pBaseA;
std::cout << "deleting pBaseB" << std::endl;
delete pBaseB;
std::cout << "deleting pBaseDB" << std::endl;
delete pBaseDB;
std::cout << "deleting pBaseCloneOfA" << std::endl;
delete pBaseCloneOfA;
std::cout << "deleting pBaseCloneOfB" << std::endl;
delete pBaseCloneOfB;
std::cout << "deleting pBaseCloneOfDB" << std::endl;
delete pBaseCloneOfDB;
std::cout << "deleting pBCloneOfDB" << std::endl;
delete pBCloneOfDB;
return 0;
}
输出为:
deleting pBaseA
I was an A
I was a Base
deleting pBaseB
I was a B
I was a Base
deleting pBaseDB
I was a DB
I was a B
I was a Base
deleting pBaseCloneOfA
I was an A
I was a Base
deleting pBaseCloneOfB
I was a B
I was a Base
deleting pBaseCloneOfDB
I was a DB
I was a B
I was a Base
deleting pBCloneOfDB
I was a DB
I was a B
I was a Base
假设所有涉及的类都是默认可构造的,B
不需要是cloner<B,D>
的虚拟基础,并且可以删除virtual
来自CCD_ 9的关键字。否则,B
必须是虚拟基础使得CCD_ 11的非默认构造函数可以由CCD_,虽然CCD_ 13不是CCD_。
在C++11中,我们有可变模板,你可以不使用虚拟模板为cloner<B,D>
提供"全能型"模板构造函数,通过它可以转发任意构造函数从CCD_ 16到CCD_。这是一个例子:
#include <iostream>
template<class B, class D>
struct cloner : B
{
B *clone() const override {
return new D(dynamic_cast<D const&>(*this));
}
~cloner() override {}
// "All purpose constructor"
template<typename... Args>
explicit cloner(Args... args)
: B(args...){}
};
struct Base
{
explicit Base(int i)
: _i(i){}
virtual ~Base() {
std::cout << "I was a Base storing " << _i << std::endl;
};
virtual Base* clone() const = 0;
protected:
int _i;
};
struct A : cloner<Base,A>
{
explicit A(int i)
: cloner<Base,A>(i){}
~A() override {
std::cout << "I was an A storing " << _i << std::endl;
};
};
struct B : cloner<Base,B>
{
explicit B(int i)
: cloner<Base,B>(i){}
~B() override {
std::cout << "I was a B storing " << _i << std::endl;
};
};
struct DB : cloner<B,DB>
{
explicit DB(int i)
: cloner<B,DB>(i){}
~DB() override {
std::cout << "I was a DB storing " << _i << std::endl;
};
};
int main()
{
Base * pBaseA = new A(1);
Base * pBaseB = new B(2);
Base * pBaseDB = new DB(3);
Base * pBaseCloneOfA = pBaseA->clone();
Base * pBaseCloneOfB = pBaseB->clone();
Base * pBaseCloneOfDB = pBaseDB->clone();
B * pBCloneOfDB = dynamic_cast<B*>(pBaseDB->clone());
std::cout << "deleting pA" << std::endl;
delete pBaseA;
std::cout << "deleting pB" << std::endl;
delete pBaseB;
std::cout << "deleting pDB" << std::endl;
delete pBaseDB;
std::cout << "deleting pBaseCloneOfA" << std::endl;
delete pBaseCloneOfA;
std::cout << "deleting pBaseCloneOfB" << std::endl;
delete pBaseCloneOfB;
std::cout << "deleting pBaseCloneOfDB" << std::endl;
delete pBaseCloneOfDB;
std::cout << "deleting pBCloneOfDB" << std::endl;
delete pBCloneOfDB;
return 0;
}
输出为:
deleting pA
I was an A storing 1
I was a Base storing 1
deleting pB
I was a B storing 2
I was a Base storing 2
deleting pDB
I was a DB storing 3
I was a B storing 3
I was a Base storing 3
deleting pBaseCloneOfA
I was an A storing 1
I was a Base storing 1
deleting pBaseCloneOfB
I was a B storing 2
I was a Base storing 2
deleting pBaseCloneOfDB
I was a DB storing 3
I was a B storing 3
I was a Base storing 3
deleting pBCloneOfDB
I was a DB storing 3
I was a B storing 3
I was a Base storing 3
您可以做的是通过整个继承来传播基等级制度,但我认为这对现在,每进一步派生一个类,都会得到一个全新的层次结构多态性将是徒劳的。
#include <iostream>
class Base
{
public:
virtual ~Base() {};
virtual Base* clone() const = 0;
};
template<class Derived> class BaseCopyable : Base
{
public:
virtual Base* clone() const
{
return new Derived(static_cast<Derived const&>(*this));
}
};
struct Default;
template<typename Self, typename Arg>
struct SelfOrArg {
typedef Arg type;
};
template<typename Self>
struct SelfOrArg<Self, Default> {
typedef Self type;
};
template<typename Derived = Default>
class A : public BaseCopyable< typename SelfOrArg<A<Derived>, Derived>::type >
{
};
class derivedA : A<derivedA> {
};
尽管这仍然有坏的返回类型的缺点CCD_ 18。使用经典的virtual constructor
习语,您可以得到说类似的话的能力
void func(Derived& d) {
// thanks to covariant return types Derived::clone returns a Derived*
Derived* d2 = d.clone();
delete d2;
}
这在你的计划中是不可能的,尽管很容易实现通过调整CCD_ 20中的返回类型。
只需编写一个宏来摆脱样板:)
- 如何在没有数据拷贝的情况下从指针创建一个Eigen VectorXd对象
- 与浅拷贝构造函数和深拷贝构造函数混淆
- 使用复制构造函数修复浅拷贝
- C++ 一个lambda浅拷贝const Type&如果它被赋予一个命名捕获,如[copy=val](){}?
- 如何找到C++的伪拷贝操作
- 是否可以在C++中拼接缓冲区,零拷贝?
- 特征稀疏矩阵的零拷贝构造
- 在构造函数中浅拷贝字符串数组
- 如何将深拷贝构造函数实现到链表中?
- 为什么移动语义与动态 mem 分配中的浅拷贝具有相同的行为
- 在函数中传递带有指针成员的结构是浅拷贝或深拷贝在 C 中
- C++ 如何为地图创建浅拷贝构造函数
- 将 Android 内存映射到具有零拷贝的 GraphicBuffer
- 浅拷贝到协议缓冲区的字节字段中
- C++ 标准::字符串意外更改。我认为这个问题是关于深和浅拷贝的
- 如何正确制作抽象类的深拷贝?
- 为什么下面的类不对数组 arr 进行浅拷贝?
- 使用聚合初始化时,是否可以将无拷贝置换到地图中
- 将C 拷贝托转换为Python
- 在C++中使用浅拷贝而不是引用的原因