在运行时将指针分配给多态类

Assign pointer to polymorphic class in runtime

本文关键字:多态 分配 指针 运行时      更新时间:2023-10-16

类A包含一个指向抽象类B的指针(仅实现了头):

// A.h
#include "B.h"
class A {
   public:
   A();
   virtual ~A();
   pointBto(B* b_);   // { this.b = b_;  }
   private:
   B* b;
}

// B.h
class B {
    public:
    B();
    virtual ~B();
    virtual void b_method() = 0;
}

类C和D继承B.

// C.h
#include "B.h"
Class C : public B {
    public:
    C();
    ~C();
    virtual b_method();
}
// D.h
#include "B.h"
Class D : public B {
    public:
    D();
    ~D();
    virtual b_method();
}

应用程序读取一个字符串,并根据这个字符串创建一个C或D类的新对象,并将b指向创建的对象。

注意:我不想创建一个无尽的链

if (string_ == "C")
{
   a_.pointBto(new C());
}
else if (string_ == "D")
{
   a_.pointBto(new D());
}
else ...

只需创建一个std::map<std::string, std::function<B*(/*...*/)>>:

static const std::map<std::string, std::function<B*(/*...*/)>> factory = {
    { "C", [](/*...*/){ return new C(/*...*/); },
    { "D", [](/*...*/){ return new D(/*...*/); },
};
a_.pointBto(factory[string_](/*arguments*/));

您要查找的内容通常被称为"虚拟构造函数"。我通常不喜欢这种结构,但它可以使用例如"克隆"习语来实现。类似以下内容:

struct Parent {
    virtual Parent* clone(/*??? arg*/)  = 0;
};
struct Child1 : Parent {
    /*virtual */ Parent clone(/*??? arg*/) { return new Child1(/*arg*/); }
};
/* Child 2 */
Parent* make_parent(Choice arg) {
    static std::map<Choice, Parent*> factory({{ch1, new Child1()}, {ch2, new Child2()}};
    return factory.find(arg).second->clone(/**/);
}

最大的问题是clone参数被简化为某种blob,这需要强制转换。

如果您想避免每次添加新的派生类时都会扩展If-else块(或其他类似的集中式机制),那么可以让派生类型自己注册。

检查这个线程的技巧如何做到:

有没有一种方法可以从包含对象类名的字符串中实例化对象?

(注意,对于给定的解决方案,字符串不需要与类名相同)。本质上,你仍然有一个从字符串到工厂函数的映射,即

map< std::string, std::function<B*()> >

不同之处在于,负责将回调添加到映射的代码是定义派生类的地方。