在类构造函数中使用指针

3

我正在进行一个个人项目,我需要一个动态工厂。 目前我有以下“系统”:

class Action { ...} // Which is abstract
class A : public Action { ... }
class B : public Action { ... }
class C : public Action { ... }

...

std::map<std::string, Action *> _actions;
_action.insert( { "A", new A() } );
_action.insert( { "B", new B() } );
_action.insert( { "C", new C() } );

Action * act = _actions.find("B")->second; // Get action's pointer

但我对这种解决方案并不满意,因为即使我从未使用这些操作,它们也会在启动时被实例化并在整个应用程序的生命周期中保留在内存中,如果我想要一个“干净”的对象,我需要动态地将对象强制转换以确定其类型,并调用复制构造函数... 我真的不喜欢这个解决方案,因为我必须“硬编码”所有情况...

我不知道我所想象的解决方案是否真的可行,但这是我的想法:

我保留以前的类层次结构,它是:

class Action { ...} // Which is abstract
class A : public Action { ... }
class B : public Action { ... }
class C : public Action { ... }

但是我想以不同的方式使用地图:

std::map<std::string, POINTER_ON_CLASS_CONSTRUCTOR> _actions;
_actions.insert( { "A", &A::A } );
_actions.insert( { "B", &B::B } );
_actions.insert( { "C", &C::C } );

Action * act = new (_actions.find("B")->second);

总之,我的想法是:

我想在每个我想映射的构造函数中将一个关键字与指针相对应,然后根据关键字动态实例化一个基于操作的对象。

非常感谢您的帮助,如果您有解决此问题的建议,请不要犹豫提交 :)


背景:

我正在为我的软件创建一个CLI,如果我想编写此解决方案,则是将操作的第一个单词与相关操作进行映射。

例如:如果我输入“add file.txt”,“add”将是我的映射的键,以检索类“AddAction”的“clean”实例(它是操作的子类 - 它是所有基于操作的类共同的抽象类)。

编辑:在发布此问题之前,我已经在网上和这个论坛上搜索过了,但是我没有找到我需要的东西。 :/


我删除了那个STL标签,因为您似乎没有使用SGI STL。请参阅“STL”和“C ++标准库”之间有什么区别? - Brian61354270
1
为每个类添加一个静态工厂方法,只需调用 new 并存储指向它们的指针。 - Chris Dodd
构造函数的地址不能被获取 - 构造函数没有名称 - Ted Lyngmo
2个回答

7
您可以将名称映射到工厂函数,然后每次需要创建新实例时调用这些函数。将其包装在 unique_ptr 中将在使用后提供所需的销毁。 在线链接
std::unordered_map<std::string, std::function<std::unique_ptr<Action>()>> ACTIONS = {
  {"A", [] { return std::make_unique<A>(); }},
  {"B", [] { return std::make_unique<B>(); }},
  {"C", [] { return std::make_unique<C>(); }}
};

int main() {
  auto action = ACTIONS["A"]();
}

2
您可以使用克隆模式来避免需要dynamic_cast对象以确定调用哪个复制构造函数,例如:
class Action {
public:
    virtual ~Action() {};
    virtual Action* clone() = 0;
    ...
};

class A : public Action {
public:
    Action* clone() { return new A(*this); }
    ...
};

class B : public Action {
public:
    Action* clone() { return new B(*this); }
    ...
};

class C : public Action {
public:
    Action* clone() { return new C(*this); }
    ...
};

...

std::map<std::string, Action*> _actions;
_action.insert( { "A", new A } );
_action.insert( { "B", new B } );
_action.insert( { "C", new C } );

Action *act = _actions["B"]->clone(); // see Note below...
...
delete act;

注意:如果您不需要验证返回的迭代器,则没有理由使用map :: find()。相反,更容易使用map :: operator [] 或 map :: at(),如果要在未找到指定键时引发错误。

但是,如果您不想在 map 中存储实际对象,则可以改用工厂函数(无法获取构造函数的指针),例如:

<code>class Action { ... }
class A : public Action { ... }
class B : public Action { ... }
class C : public Action { ... }

...

using ActionFactoryFunc = Action* (*)();

std::map<std::string, ActionFactoryFunc> _actions;
_action.emplace( "A", []() -> Action* { return new A; } );
_action.emplace( "B", []() -> Action* { return new B; } );
_action.emplace( "C", []() -> Action* { return new C; } );

Action *act = _actions["B"]();
...
delete act;
</code>

最后,你应该使用std::unique_ptr<Action>而不是裸指针Action*,例如:

#include <memory>

class Action {
public:
    virtual ~Action() = default;
    virtual std::unique_ptr<Action> clone() = 0;
    ...
};

class A : public Action {
public:
    std::unique_ptr<Action> clone() override { return std::make_unique<A>(*this); }
    ...
};

class B : public Action {
public:
    std::unique_ptr<Action> clone() override { return std::make_unique<B>(*this); }
    ...
};

class C : public Action {
public:
    std::unique_ptr<Action> clone() override { return std::make_unique<C>(*this); }
    ...
};

...

std::map<std::string, std::unique_ptr<Action>> _actions;
_action.emplace( "A", std::make_unique<A>() );
_action.emplace( "B", std::make_unique<B>() );
_action.emplace( "C", std::make_unique<C>() );

auto act = _actions["B"]->clone();
...

或者:

#include <memory>

class Action { ... }
class A : public Action { ... }
class B : public Action { ... }
class C : public Action { ... }

...

using ActionFactoryFunc = std::unique_ptr<Action> (*)();

std::map<std::string, ActionFactoryFunc> _actions;
_action.emplace( "A", []() -> std::unique_ptr<Action> { return std::make_unique<A>(); } );
_action.emplace( "B", []() -> std::unique_ptr<Action> { return std::make_unique<B>(); } );
_action.emplace( "C", []() -> std::unique_ptr<Action> { return std::make_unique<C>(); } );

auto act = _actions["B"]();
...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接