奇怪地重复出现的模板模式多态副本(C ++)中的继承 [英] Inheritance in curiously recurring template pattern polymorphic copy (C++)
问题描述
我正在使用CRTP将克隆方法添加到继承的类中,例如:
I'm using CRTP to add a clone method to inherited classes, for example:
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的类,例如:
But if I have a class that inherits from B, for example:
class differentB : public B;
然后clone()不返回类型为differentB的对象,而是返回B.除了在differentB中编写新的clone()方法之外,还有什么方法可以解决此问题?
Then clone() doesn't return an object of type differentB, it returns a B. Besides writing a new clone() method in differentB, is there some way to fix this?
感谢阅读!
推荐答案
这是我对此问题的答案的重做
您的意图是将所有派生类都放在层次结构中
从其基类继承可克隆性(多态副本),因此
您也不需要为它们中的每一个提供覆盖
clone()
,但您尝试使用类模板的CRTP解决方案
BaseCopyable
只能以这种方式赋予克隆性
直接从Base
派生的类,而不是从派生的类派生的类
来自此类派生类.
Your intent is to have all the derived classes in your hierarchy
inherit cloneability (polymorphic copy) from their base class so
that you do not also need to provide each of them with an override
of clone()
, but your attempted CRTP solution with class template
BaseCopyable
can only only confer cloneability in this way upon
classes immediately derived from Base
, and not upon classes derived
from such derived classes.
我不认为不可能直接传播克隆性
通过授予仅一次"可克隆性来任意深度地构建层次结构
最具体的类.您必须明确授予每个
具体类,但是您可以通过其基类来做到这一点,
通过使用CRTP而不重复覆盖clone()
在父类中将可复制性从父类传递给子类的模板
层次结构.
I do not think it is not possible to propagate cloneability right down an
arbitrarily deep hierarchy by confering cloneability "just once" at
the topmost concrete classes. You must explicitly confer it on each
concrete class, but you can do this via their base classes and
without repetitiously overriding clone()
, by using a CRTP
template that relays cloneability from parent class to child in the
hierarchy.
很显然,适合此法案的CRTP模板与BaseCopyable
不同
需要两个模板参数:父类型和子类型.
Clearly, a CRTP template that fits this bill will differ from BaseCopyable
by requiring two template parameters: the parent type and the child type.
C ++ 03解决方案如以下程序所示:
A C++03 solution is as illustrated by the following program:
#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
必须是虚拟基础
因此D
的构造函数可以调用B
的非默认构造函数,
尽管B
不是D
的直接基础.
Provided that all the classes involved are default constructible, B
need not be a virtual base of cloner<B,D>
and you can remove the virtual
keyword from struct cloner : virtual B
. Otherwise, B
must be a virtual base
so that a non-default constructor of B
can be called by a constructor of D
,
although B
is not a direct base of D
.
在C ++ 11中,我们拥有可变参数模板,您可以不用虚拟
通过为cloner<B,D>
提供通用"来完全继承
模板构造函数,通过它可以转发任意构造函数
从D
到B
的参数.这是一个说明:
In C++11, where we have variadic templates, you can do without virtual
inheritance altogether by furnishing cloner<B,D>
with an "all-purpose"
template constructor through which it can forward arbitrary constructor
arguments from D
to B
. Here is an illustration of that:
#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
这篇关于奇怪地重复出现的模板模式多态副本(C ++)中的继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!