Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
提高克隆模式的安全性 如果想在C++中实现克隆> /COD>模式,他可能不确定安全性,因为派生类可能忘记重写它: struct A { virtual A* Clone() const { return new A(*this); } } struct B : A { int value; }; int main() { B b; // oops auto b_clone = b.Clone(); delete b_clone; } 在C++中,如何改进C++中的克隆< /代码>模式?_C++_Design Patterns_Crtp_Cloneable - Fatal编程技术网

提高克隆模式的安全性 如果想在C++中实现克隆> /COD>模式,他可能不确定安全性,因为派生类可能忘记重写它: struct A { virtual A* Clone() const { return new A(*this); } } struct B : A { int value; }; int main() { B b; // oops auto b_clone = b.Clone(); delete b_clone; } 在C++中,如何改进C++中的克隆< /代码>模式?

提高克隆模式的安全性 如果想在C++中实现克隆> /COD>模式,他可能不确定安全性,因为派生类可能忘记重写它: struct A { virtual A* Clone() const { return new A(*this); } } struct B : A { int value; }; int main() { B b; // oops auto b_clone = b.Clone(); delete b_clone; } 在C++中,如何改进C++中的克隆< /代码>模式?,c++,design-patterns,crtp,cloneable,C++,Design Patterns,Crtp,Cloneable,提出了一个更一般性的问题: 但是,C++中似乎有一个好的解决方案太普遍了——讨论的是可能的方法来执行方法重写。我更感兴趣的是发现一种有用的模式,这可能有助于使用可克隆模式。这是对其中一个答案的详细说明,建议使用typeid进行运行时检查: 使用CRTP,可以得出以下基本想法: 创建类Cloneable,该类管理派生的的克隆,并添加所有需要的运行时检查(似乎即使使用CRTP也不可能进行编译时检查) 然而,这并非小事,还必须通过Cloneable管理继承,如下所述: #include <m

提出了一个更一般性的问题:


但是,C++中似乎有一个好的解决方案太普遍了——讨论的是可能的方法来执行方法重写。我更感兴趣的是发现一种有用的模式,这可能有助于使用可克隆模式。

这是对其中一个答案的详细说明,建议使用typeid进行运行时检查:

使用CRTP,可以得出以下基本想法:

创建类
Cloneable
,该类管理
派生的
的克隆,并添加所有需要的运行时检查(似乎即使使用CRTP也不可能进行编译时检查)

然而,这并非小事,还必须通过
Cloneable
管理继承,如下所述:

#include <memory>
#include <cassert>
#include <type_traits>
#include <typeinfo>

class CloneableInterface {
public:
    virtual std::unique_ptr<CloneableInterface> Clone() const = 0;
};

template <class... inherit_from>
struct InheritFrom : public inherit_from... {
};

template <class Derived, class AnotherBase = void, bool base_is_cloneable = std::is_base_of_v<CloneableInterface, AnotherBase>>
class Cloneable;

// three identical implementations, only the inheritance is different

// "no base is defined" case
template <class Derived>
class Cloneable<Derived, void, false> : public CloneableInterface {
public:
    std::unique_ptr<CloneableInterface> Clone() const override {
        assert(typeid(*this) == typeid(Derived));
    return std::make_unique<Derived>(static_cast<const Derived&>(*this));
    }
};

// Base is defined, and already provides CloneableInterface
template <class Derived, class AnotherBase>
class Cloneable<Derived, AnotherBase, true> : public AnotherBase {
   ...
};

// Base is defined, but has no CloneableInterface
template <class Derived, class AnotherBase>
class Cloneable<Derived, AnotherBase, false> : public AnotherBase, public CloneableInterface {
    ...
};
#包括
#包括
#包括
#包括
类克隆接口{
公众:
虚拟std::unique_ptr Clone()const=0;
};
模板
结构继承自:公共继承自。。。{
};
模板
类可克隆;
//三个相同的实现,只是继承不同
//“未定义基础”案例
模板
类可克隆:公共可克隆接口{
公众:
std::unique_ptr Clone()常量覆盖{
断言(typeid(*this)=typeid(派生));
return std::make_unique(静态_cast(*this));
}
};
//Base已定义,并已提供CloneableInterface
模板
类可克隆:另一个公共基{
...
};
//Base已定义,但没有CloneableInterface
模板
类Cloneable:public-AnotherBase,public-CloneableInterface{
...
};
用法示例:

class Base : public Cloneable<Base> {
};

// Just some struct to test multiple inheritance
struct Other {
};

struct Derived : Cloneable<Derived, InheritFrom<Base, Other>> {
};

struct OtherBase {
};

struct OtherDerived : Cloneable<OtherDerived, InheritFrom<OtherBase>> {
};

int main() {
    // compiles and runs
    auto base_ptr = std::make_unique<Base>();
    auto derived_ptr = std::make_unique<Derived>();
    auto base_clone = base_ptr->Clone();
    auto derived_clone = derived_ptr->Clone();

    auto otherderived_ptr = std::make_unique<OtherDerived>();
    auto otherderived_clone = otherderived_ptr->Clone();
}
类库:公共可克隆{
};
//只是一些测试多重继承的结构
结构其他{
};
派生结构:可克隆{
};
结构OtherBase{
};
结构Other派生:可克隆{
};
int main(){
//编译并运行
auto base_ptr=std::make_unique();
自动派生的_ptr=std::使_唯一();
auto base_clone=base_ptr->clone();
自动派生的克隆=派生的克隆->克隆();
auto-otherderived_ptr=std::make_unique();
auto otherderived_clone=otherderived_ptr->clone();
}
欢迎任何批评和改进建议

C++17及更新版本提供了。理论上,您可以创建一个克隆函数,返回
std::any*

struct A {
    virtual std::any* Clone() const {
        return new A(*this);
    }
}

struct B : A {
    int value;
    // I suppose it doesn't have to be virtual here, 
    // but just in case we want to inherit the cloning capability from B as well
    virtual std::any* Clone() const { // Note: you still need to override this function
        return new B(*this);          // in the lower levels, though
    }
};
// Note: I'm still on MSVS2010, so this C++17 code is untested.
// Particularly problematic could be this main
int main() {
   B b;
   // Here is the clone
   auto b_clone = std::any_cast<B*>(b.Clone());
   delete b_clone;
}
结构A{ 虚拟std::any*Clone()常量{ 返回新的A(*本); } } 结构B:A{ int值; //我想这里不必是虚拟的, //但为了以防万一,我们也想从B继承克隆功能 虚拟std::any*Clone()常量{//注意:您仍然需要重写此函数 返回新的B(*this);//但是在较低的级别 } }; //注意:我仍然在MSVS2010上,所以这段C++17代码未经测试。 //特别有问题的可能是这一主要问题 int main(){ B B; //这是克隆人 auto b_clone=std::any_cast(b.clone()); 删除b_克隆; }
同样,这是未经测试的,但在理论上应该是可行的。

派生类不重写它与安全无关。基类中缺少虚拟析构函数,并且使用裸指针。@VTT对于这些琐碎的类来说是okNo,这不正常,但却是导致未定义行为的主要原因@datell首先,示例中没有析构函数,即使是编译器生成的析构函数。所以我不相信你,这是一个UBIt就是UB,看。好吧,好吧,我明白你的笑话,把所有的责任都交给那个叫它的人,但这并不是一种模式改进:)也许我误解了你对当前模式的问题。你对当前模式有什么问题?@Chipster问题是你可能会忘记在B中覆盖。我想我误解了。这实际上似乎非常合法,尽管我从未使用过
std::any
@datell I recon。我的理念是,无论子对象是否重写它,它都只能返回
a*
,而不是您所期望的
B*
。这就解决了这个问题。不过,我想我的解决方案中仍然没有任何东西可以阻止您不重写该函数。可能得考虑一下。