【问题标题】:c++ Object creating new instances of same typec ++对象创建相同类型的新实例
【发布时间】:2014-05-24 17:05:48
【问题描述】:

有没有办法让对象可以创建自己类型的新对象,而无需指定此类型?

class Foo {
public:
    virtual Foo* new_instance() {
        return new type_of(this); // Some magic here
    }
};

class Bar: public Foo {

};

Foo* a = new Foo();
Foo* b = new Bar();
Foo* c = a->new_instance();
Foo* d = b->new_instance();

我现在希望c 的类型为Foo,而d 的类型应为Bar

【问题讨论】:

  • 你想定义一个单例/工厂吗?
  • 不是单身人士。不知道工厂能不能解决?

标签: c++ object types instantiation


【解决方案1】:

您可以使用 Mixin 添加工厂类。对于工厂函数来说,这似乎相当复杂,当然也更难理解。

#include <typeinfo>
#include <cassert>
#include <iostream>

template<class T> class WithFactory: public T {
public:
    WithFactory<T>* new_instance() override {
        return new WithFactory<T>( );
    }
};

class FactoryFunction {
    virtual FactoryFunction* new_instance() = 0;
};

class Foo_: public FactoryFunction {
public:
    virtual void f() {
        std::cout << "Foo" << std::endl;
    }
};
typedef WithFactory<Foo_> Foo;

class Bar_: public Foo {
public:
    virtual void f() override {
        std::cout << "Bar" << std::endl;
    }
};
typedef WithFactory<Bar_> Bar;

int main()
{
    Foo* a = new Foo();
    Foo* b = new Bar();
    Foo* c = a->new_instance();
    Foo* d = b->new_instance();

    assert( typeid(a) == typeid(c) );
    assert( typeid(b) == typeid(d) );

    a->f();
    b->f();
    c->f();
    d->f();

    return 0;
}

输出是

Foo
Bar
Foo
Bar

【讨论】:

    【解决方案2】:

    简短回答:不,没有办法让这种魔法发生。

    您可以使用宏来更轻松地覆盖子类中的函数,或者创建一个使用“奇怪重复的模板模式”的中间类:

    template <typename T>
    class FooDerived : public Foo
    {
    public:
        T* new_instance() {
            return new T();
        }
    };
    
    class Bar : public FooDerived<Bar>
    {
    };
    
    Foo* a = new Bar();
    Foo* b = a->new_instance(); // b is of type Bar*
    

    但这肯定不值得。

    【讨论】:

    • 但是当我以后想添加新的 Bar 子类时,我也必须将 Bar 设为模板类。这会破坏客户端。
    • 不,您不必将 Bar 设为模板,原因与 Foo 不是模板相同。如果你真的想这样做(但你为什么要这样做?!!),你可以让FooDerived 接受两个参数:template &lt;typename Derived, typename Base = Foo&gt; class FooDerived : public Base。然后你可以做class Buzz : public FooDerived&lt;Buzz, Bar&gt;
    • 好的,同样的论点:当我想引入一个从 Bar 派生的新类 Buzz 时会发生什么?
    • 第一:我的回答基本上是“不要这样做”。我建议使用此处提出的模板解决方案,只是为了节省一些输入。第二:你没看懂我上面的评论!当您将FooDerived 更改为接受Base 参数时,您可以使用any Foo 派生类作为基类,包括Buzz。如果你想创建一个扩展 Buzz 的类 Barbara,你可以这样做:class Barbara : public FooDerived&lt;Barbara, Buzz&gt;每个层次结构只需要一个模板,而不是每个类一个。
    【解决方案3】:

    简单的解决方案:

    class Foo {
    public:
        virtual Foo* new_instance() {
            return new Foo();
        }
    };
    
    class Bar: public Foo {
    public:
        virtual Foo* new_instance() {
            return new Bar();
        }
    };
    

    【讨论】:

    • 是的,但问题是是否有一个(非直截了当的)解决方案可以让我不指定类型,因此不会在每个派生类中重载跨度>
    【解决方案4】:

    是的,你就是这么做的

    virtual Foo* new_instance() { return new Foo(); }
    

    然后在每个派生类中再次重载它以执行相同的操作(尽管我更喜欢模板方法来处理这类事情)

    【讨论】:

    • 创建自己类型的新对象,不指定此类型
    • 我不相信在 C++ 中,如果您使用模板系统为你,否则没有。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-18
    • 2011-04-14
    • 2011-05-24
    • 1970-01-01
    相关资源
    最近更新 更多