我正在使用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.除了在differentB中编写一个新的clone()方法之外,有没有办法解决这个问题?
感谢阅读!
答案 0 :(得分:3)
这是我对this question
的回答的修改您的意图是在层次结构中包含所有派生类
从它们的基类继承可克隆性(多态复制)
你不需要为每个人提供覆盖
clone()
,但您尝试使用类模板的CRTP解决方案
BaseCopyable
只能以这种方式赋予克隆性
类立即派生自Base
,而不是派生类
来自这样的派生类。
我认为不可能传播克隆性
通过赋予“只有一次”的克隆性来任意深层次
最顶尖的具体课程。你必须在每个上明确赋予它
具体的类,但你可以通过他们的基类和
不使用CRTP重复覆盖clone()
将可克隆性从父类传递到子类的模板
层次结构。
显然,符合此法案的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
来自struct cloner : virtual B
的关键字。否则,B
必须是虚拟基础
以便B
的构造函数可以调用D
的非默认构造函数,
虽然B
不是D
的直接基础。
在C ++ 11中,我们有可变参数模板,你可以不用虚拟
通过为cloner<B,D>
提供“通用”来完全继承
模板构造函数,它可以通过它转发任意构造函数
从D
到B
的参数。这是一个例子:
#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
答案 1 :(得分:0)
您可以做的是通过整个继承传播基础 层次结构,但我认为这不会特别有用 每个进一步派生的类,你现在得到一个全新的层次结构和所有 多态性将是徒劳的。
#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> {
};
虽然这仍有缺陷的返回类型
BaseCopyable
。有了经典的virtual constructor
成语,你就会得到
能够说出类似的话:
void func(Derived& d) {
// thanks to covariant return types Derived::clone returns a Derived*
Derived* d2 = d.clone();
delete d2;
}
虽然很容易实现,但您的方案无法做到这一点
通过调整BaseCopyable
中的返回类型。
只需编写一个宏来摆脱样板:)