奇怪地重复出现的模板模式多态副本(C ++)中的继承 [英] Inheritance in curiously recurring template pattern polymorphic copy (C++)

查看:80
本文介绍了奇怪地重复出现的模板模式多态副本(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>提供通用"来完全继承 模板构造函数,通过它可以转发任意构造函数 从DB的参数.这是一个说明:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆