(C ++)如何基于条件声明对象类成员

时间:2013-12-13 16:32:26

标签: c++ scope

我正在开发一个面向对象的tic tac toe游戏,我遇到了问题。我的一个类充当游戏的主控制器并控制所有其他对象。下面是该类的剥离版本。

最终用户可以选择一到两个玩家。因此,我没有必要创建第二个玩家和一个ai玩家。游戏只需要一个或另一个。正如您在下面看到的,我尝试使用if语句来解决问题,但是对象没有范围。

如何根据传递给Game构造函数的玩家数量初始化一个或另一个对象?

谢谢!

Game.h

#include "Player.h"
#include "AIPlayer.h"

class Game 
{
    private:
        Player human;

        // I would like to put these here so they have scope
        // but it is unecessary to declare them both
        // If the user chooses one player then human2 is unecessary
        // if the user choosed two player then ai is unecessary
        AIPlayer ai;
        Player human2; 

    public: 
        Game(int players)
        {
            if (players == 1)
            {
                AIPlayer ai; // this does not have scope
            }
            else
            {
                Player human2; // this does not have scope
            }
        }
};

8 个答案:

答案 0 :(得分:6)

我的建议是从公共基类(例如,Player)派生AIPlayer和Player(或者更好的HumanPlayer),并在Game中有一个指向该基类的指针。然后构造函数实例化AIPlayer或HumanPlayer并将其分配给指针。

AIPlayer和HumanPlayer之间不同的任何方法都应该在基类Player中声明为虚方法,然后在派生类中实现。

答案 1 :(得分:1)

您可能想要做的是指向抽象Player超类作为游戏成员的指针,并将其分配给new AIPlayernew HumanPlayer,具体取决于播放器。

类似的东西:

#include "Player.h"
#include "AIPlayer.h"
#include "HumanPlayer.h"

class Game 
{
    private:
        Player* other_player;

    public: 
        Game(int players)
        {
            if (players == 1)
            {
                other_player = new AIPlayer;
            }
            else
            {
                other_player = new HumanPlayer;
            }
        }
};

答案 2 :(得分:1)

你应该为Player和AIPlayer创建一个(抽象)基类,例如:

abstract class Player
{
    virtual void MakeMove(GameBoard& b);
}

class HumanPlayer : public Player
{...}

class AIPlayer : public Player
{...}

然后在游戏中,你可以简单地存储两个Player实例。

答案 3 :(得分:1)

类继承是一个很好的解决方案。你创建一个基类并从中派生出其他玩家,如下所示:

class Player{
  virtual int move(int)=0;
}

class AIPlayer: Player{
  virtual int move(int);
}

class HumanPlayer: Player{
  virtual int move(int);
}

答案 4 :(得分:1)

你对这里的“范围”有一点误解。类声明不是范围 - 它只是支持该类的数据和函数的声明。范围存在于函数内部。

class A
{
    int a;
};

aA的成员,但由于它从未被实例化,因此它不属于任何范围。

void func()
{
    A a;
}

func具有已定义的范围,a是其中的一部分。当func结束时,a超出范围并被销毁。

现在,问题:解决问题的最简单方法是使用继承。它将阻止您在整个代码中进行各种条件检查,以确定哪些对象有效,哪些对象无效。一个例子如下:

class Player
{
public:
    virtual void Move() = 0; // pure virutal function 
};

class HumanPlayer()
{
public:
    ...
    virtual void Move() { ... }
};

class AIPlayer()
{
public:
    ...
    virtual void Move() { ... }
};

class Game
{
public:
    Game(unsigned int humanPlayerCount = 0)
    {
        if (humanPlayerCount == 0)
        {
            m_player1.reset(new AIPlayer());
            m_player2.reset(new AIPlayer());
        }
        else if (humanPlayerCount == 1)
        {
            m_player1.reset(new HumanPlayer());
            m_player2.reset(new AIPlayer());
        }
        else // assume it is 2
        {
            m_player1.reset(new HumanPlayer());
            m_player2.reset(new HumanPlayer());
        }
    }
    ...
private:
    std::unique_ptr<Player> m_player1;
    std::unique_ptr<Player> m_player2;
};

构造完成后,你会对它们进行同样的处理(从Game的观点来看它们之间没有区别。)

答案 5 :(得分:0)

你无法做你想做的事。 您的问题的解决方案是使用继承。 创建一个没有任何这两个字段的基类,然后创建2个派生类,并在每个字段中放置一个字段。

答案 6 :(得分:0)

正如您所发现的那样,您不能使用 if 语句,因为if语句是在运行时执行的,但是必须在编译时确定类的成员。 / p>

这给你留下了其他几个选择:

  • 您可以随时声明两个人类玩家对象和一个AIPlayer对象,并在任何特定游戏中保留一个未使用的对象。 (这就是我要做的事,除非这样做会产生巨大的开销,因为这是最简单的方法)

  • 您可以声明指向所有三个对象的指针,然后使用new运算符动态分配您想要使用的对象。 (完成后,请务必使用删除来取消分配)

  • 你可以创建Game的几个子类(例如OnePlayerGame和TwoPlayerGame),这样子类就有你需要的额外对象(例如Game只声明了human1,OnePlayerGame添加了ai,而TwoPlayerGame添加了human2)

答案 7 :(得分:0)

模板怎么样? 创建对象时选择类型(AIPlayer或播放器)