【问题标题】:Using containers of abstract class to hold children classes使用抽象类的容器来保存子类
【发布时间】:2019-10-23 21:07:12
【问题描述】:

我想从这个接口继承几个类:

class IPlayer {

public:
     virtual ~IPlayer() {}

     virtual void doSomething() = 0;

protected:
     std::string m_name;

};

这里有一个类,需要从上面继承:

class Jack : public IPlayer {

public:
      Jack(std::string t_name)
      {
             m_name = t_name;
      }

      ~Jack() { }

      void doSomething()
      {
              /* do a bunch of stuff */
      }

};

请记住,我们还有其他类以相同的方式从 IPlayer 继承,例如 BobAlice

现在假设我想为Jacks、Bobs 和Alices 创建一个容器,这样我就可以将它们重新组合到同一个变量中。在这种状态下,对我来说是不可能的,因为 IPlayer 没有 ctor,因此不能用作向量或列表等对象的模板。 (至少这是我的理解)

IPlayerJack 之间有一个类会更好吗,它只实现ctor 和dtor,然后让其他方法纯虚,供孩子们利用;

使IPlayer(和/或任何未来的接口)继承自与上述仅实现ctor和dtor相同的类,只是为了使IPlayer可用于容器?

【问题讨论】:

  • 您将使用指向IPlayer 的(可能是智能的)指针容器,如std::vector<IPlayer*>std::vector<std::unique_ptr<IPlayer>>IPlayer 类已经有一个构造函数——一个默认的;无法创建它的实例的原因是因为它是抽象的。添加更多构造函数不会改变这一事实。
  • @IgorTandetnik 对,这是最有效的选择。为什么/如何使用指针容器绕过这个问题?
  • 绕过什么问题?我不确定我是否完全掌握了困难的性质。
  • 如果不是 ctor,抽象类的内在特性是什么使它无法作为容器的实例?
  • 你不能创建一个抽象类的实例,句号;无论是作为容器的元素还是其他。这就是纯虚函数的意义所在。你不能有std::vector<IPlayer>,因为你不能写IPlayer player;IPlayer* player = new IPlayer;

标签: c++ c++11 inheritance interface virtual-inheritance


【解决方案1】:

IPlayer 可以有一个构造函数,实际上有一个由编译器提供。

这是一种将玩家列表保存在 IPlayer 的静态成员中的方法。但该列表不必在 IPlayer 中。

#include <memory>
#include <vector>

// forward declaration
class IPlayer;

using Players = std::vector<PlayerPtr>;

class IPlayer {
public:
    virtual ~IPlayer() {
    }
    static void addPlayer(IPlayer& player) {
        mPlayers.push_back(std::make_unique<IPlayer>(player));
    }
private:
    static Players mPlayers;
};

Players IPlayer::mPlayers;

class Bob : public IPlayer {
};

void run() {
    Bob bob;
    IPlayer::addPlayer(bob);
}

【讨论】:

    【解决方案2】:

    其实这些类没有问题。 IPlayer 可能是一个抽象类,但您永远不需要创建此类的实例。你可以完美地声明一个指向 IPlayers 的指针向量,只要向量的元素都指向非抽象子类。

    Jack* j = new Jack("jack");
    std::vector<IPlayer*> v = {j};
    

    这段代码非常好,因为没有创建 IPlayer 的实例。

    【讨论】:

    • 虽然这是正确的,但重要的是要意识到使用裸指针不是一个好方法。谁来删除 Jack 播放器?
    • @rm1948 我使用裸指针来简化我的代码。当然,OP 可以使用智能指针,但这是他的选择,因为我不知道什么智能指针最适合他的系统。我只是在展示它是如何实现的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    • 2018-02-06
    • 1970-01-01
    • 2014-07-30
    • 2017-03-26
    • 2017-01-10
    相关资源
    最近更新 更多