C++ 奇怪循环模板模式多态副本(C+;+;)中的继承

C++ 奇怪循环模板模式多态副本(C+;+;)中的继承,c++,polymorphism,crtp,C++,Polymorphism,Crtp,我正在使用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

我正在使用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...
class differentB : public B;
然后clone()不返回differentB类型的对象,而是返回一个B。除了在differentB中编写一个新的clone()方法外,还有什么方法可以解决这个问题吗


谢谢你的阅读

您可以做的是在整个继承中传播基 层次结构,但我认为这对于 现在,每一个进一步的派生类都会得到一个全新的层次结构和 多态性将是徒劳的

#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
中调整返回类型


只要写一个宏就可以摆脱这个样板:)

这是我对

您的目的是在层次结构中拥有所有派生类 从基类继承可克隆性(多态副本) 您也不需要为它们中的每一个提供覆盖 属于
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;
}
假设所有涉及的类都是默认可构造的,
B
不必是
cloner
的虚拟基,您可以删除
virtual
来自结构克隆器的关键字:虚拟B。否则,
B
必须是虚拟基 因此,
D
的构造函数可以调用
B
的非默认构造函数, 虽然
B
不是
D
的直接基础

在C++11中,我们有可变模板,您可以不使用虚拟模板 通过为克隆人提供一个“通用”的 模板构造函数,通过它可以转发任意构造函数 参数从
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;
}

您可以只要求最派生的类继承自
BaseCopyable
。克隆成员函数的目的不是可以在派生类的重写中返回派生类型吗?这称为协变返回类型,非常适合该特性。
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
#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