Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;从父类创建子类,该父类为';已经草签了_C++_Class_Inheritance - Fatal编程技术网

C++ C++;从父类创建子类,该父类为';已经草签了

C++ C++;从父类创建子类,该父类为';已经草签了,c++,class,inheritance,C++,Class,Inheritance,我有一个班级叫“球员”。它的成员是简单的字符串和整数,我为每一个都有getter和setter…基本的东西:(有大量的成员,所以我只给了3个来压缩代码): PLAYER.H PLAYER.CPP 所以,是的,相当标准……现在我有了第二个类,其中一个成员函数本身就是一个Player类 电池H 好的-这是代码的方式 我已经让它做了我想做的一切,在传入和传出变量方面……所以我可以创建 Player Dave ("Dave", "Opener", 98, ....etc) 然后稍后(当我需要时)创建

我有一个班级叫“球员”。它的成员是简单的字符串和整数,我为每一个都有getter和setter…基本的东西:(有大量的成员,所以我只给了3个来压缩代码):

PLAYER.H

PLAYER.CPP

所以,是的,相当标准……现在我有了第二个类,其中一个成员函数本身就是一个Player类

电池H

好的-这是代码的方式

我已经让它做了我想做的一切,在传入和传出变量方面……所以我可以创建

Player Dave ("Dave", "Opener", 98, ....etc)
然后稍后(当我需要时)创建

所有的肉汁…好吧,我已经开始研究继承,并意识到这是我应该做的…反向转换不是问题(前几天对数组和向量进行了此操作)

我的问题是:


根据我现在所拥有的,我可以创建“玩家Dave”,然后在需要时将他传递到击球手的子类中。我如何对传统遗产进行同样的处理?我如何获取Player的特定实例(已创建),并将其用作子类Batter的特定实例的父类?据我目前推断,您需要同时创建这两个对象。

只需使用提供的对象初始化基本对象:

class Player
{
  Player(Player const&); // copy constructor (might be implicitly generated)
  ...
};

class Batter:
  public Player
{
  Batter(Player const& p, other arguments):
    Player(p),
    ...
  {
    ...
  }
};
另一方面,在您的案例中,从
Player
继承
Batter
是否是正确的工具是一个问题。将
玩家
对象传递给construction这一事实暗示了一个事实,即玩家可能会成为击球手,并且以后也可能不再是击球手。也就是说,
Batter
实际上是玩家可能暂时扮演的角色。因此,最好将
玩家
对象与角色分开,方法是使用一个独立的
角色
层次结构,其中
击球手
投手
来自
角色
,并且
玩家
有一个返回当前角色的方法,另一个可以为玩家分配另一个角色。

停止使用“父”和“子”术语,想想“基”类和“派生”类。。。其他人都这么叫他们。“Parent”和“child”可以用在太多其他方式(例如,拥有另一个对象的对象)中,因此,如果您谈论的是继承关系,则会混淆术语

派生类本身包含基类型的整个实例。当派生构造函数开始执行时,它要做的第一件事就是构造它的所有基,这是通过调用它们的构造函数来完成的。因此,派生类可以通过向其传递正确的参数来控制基类的构造方式:

class Base {
public:
  Base(std::string nm) : name(nm) { }

protected:
  std::string name;
};

class Derived : public Base {
public:
  // construct my base by passing name to it
  Derived(std::string name, int ii) : Base(name), i(ii) { }

private:
  int i;
};

Derived d("Dave Derived", 1);
这将同时创建
Base
派生的
对象(一个在另一个内部),这可能就是您想要的

如果您有一个现有的
Base
对象,并且希望派生对象的基本部分与另一个相同,则可以向其传递一个要复制的对象:

class Base {
public:
  Base(std::string nm) : name(nm) { }
protected:
  std::string name;
};

class Derived : public Base {
public:
  // construct my base by passing name to it
  Derived(std::string name, int ii) : Base(name), i(ii) { }

  // construct my base by passing another Base to it:
  Derived(const Base& b, int ii) : Base(b), i(ii) { }

private:
  int i;
};

Base b("Barry Base");
Derived d(b, 2);
这不会将现有的
Base
对象
b
放在
派生的
对象中,而是通过调用
Base
复制构造函数,使基本对象成为对象
b
的副本,因此现在有两个
Base
对象,原始的
b
d
中的一个。这更接近您的原始代码,
Batter
包含一个
Player
成员,但现在它是一个基类而不是成员


如果您确实想使用继承,第一种形式可能更合适,将参数传递给派生类,它使用这些参数创建基。

多态性的思想是,如果您有某个类:

class Batter : public Player
那么每个击球手也是一名球员。例如,如果你有一个击球手叫
dave
,你就可以在任何需要球员的地方使用
dave
。例如,您可以:

int FunctionThatDoesSomething(Player &p, string some_parameter, ...);

...

FunctionThatDoesSomething(dave, "foo", ...);
小心避免切片,这是在您意外地创建子类的基类副本时发生的(这不会保留子类特定的状态。如果您需要传递
dave
,请确保只参考
dave
,不要复制
dave
dave
不喜欢被复制。)

如何培养你的球员和击球手取决于你自己。例如,您的构造函数可能具有以下签名:

Player::Player(string name, string role, int vFFDefense);
Batter::Batter(Player &p, int vTouch, int moreStats);
在某些情况下,这可能很方便,但效率不是特别高,因为您必须创建和复制基类(对于像这样的小型类来说,效率不是什么大问题,但尝试以愚蠢的方式进行操作是没有意义的)。您最好制作一个构造函数,该构造函数接受它所需的一切,并使用子对象初始化:

Batter::Batter(string name, string role, int vFFDefense, int moreBaseStats, int vTouch, int moreStats) : Player(name, role, vFFDefense, moreBaseStats)
{
    ...

但实现最终取决于您。

这实际上取决于您希望如何分解代码。 一个给定的
玩家
除了成为一个
击球手
之外,还会成为别的什么吗?如果可以,那么最好使用聚合(与您现在的做法类似)

如果您正在聚合,那么可以使用另一个类来保存数据。您可以拥有一个PlayerInfo类或结构并聚合:

struct PlayerInfo
{
    string role_;
    int ff_defence_;
    ...
};

class Player 
{
public:
    Player(PlayerInfo const& info)
        : info_(info)
    {}
    virtual ~Player() = 0;
    virtual void doSomething();

    PlayerInfo const& getPlayerInfo() const { return info_; }
private:
    PlayerInfo info_;
};

class Batter : public Player
{
public:
    Batter(PlayerInfo const& info)
        : Player(info)
    {}
    virtual void doSomething();
};
如果您确实想要继承,那么这里的其他答案会告诉您需要做什么-构造
Batter
的实例,并将构造函数参数传递给派生类的构造函数(例如
Batter
)以对其进行初始化

仔细考虑您试图在代码中表达的内容

您希望从
Player
派生
Batter
的原因是,如果您需要在
Player
中实现的
Batter
中的虚拟函数,并且根据它是
Player
还是
Batter>执行不同的操作<
int FunctionThatDoesSomething(Player &p, string some_parameter, ...);

...

FunctionThatDoesSomething(dave, "foo", ...);
Player::Player(string name, string role, int vFFDefense);
Batter::Batter(Player &p, int vTouch, int moreStats);
Batter::Batter(string name, string role, int vFFDefense, int moreBaseStats, int vTouch, int moreStats) : Player(name, role, vFFDefense, moreBaseStats)
{
    ...
struct PlayerInfo
{
    string role_;
    int ff_defence_;
    ...
};

class Player 
{
public:
    Player(PlayerInfo const& info)
        : info_(info)
    {}
    virtual ~Player() = 0;
    virtual void doSomething();

    PlayerInfo const& getPlayerInfo() const { return info_; }
private:
    PlayerInfo info_;
};

class Batter : public Player
{
public:
    Batter(PlayerInfo const& info)
        : Player(info)
    {}
    virtual void doSomething();
};
class Player;

class PlayerBehaviour
{
public:
    virtual ~PlayerBehaviour() = 0;
    virtual void doSomething(Player* player) = 0;
};
inline PlayerBehaviour::~PlayerBehaviour() {}

class BatterBehaviour : public PlayerBehaviour
{
public:
    virtual void doSomething(Player* player) {
        if (player->isAngry()) {
            throwBatOnFloor();
        }
    }
    void throwBatOnFloor();
};

class Player {
public:
    Player(...stuff...);

    void doSomething() {
        if (behaviour_.get()) {
            behaviour_->doSomething(this);
        }
    }
private:
    auto_ptr<PlayerBehaviour> behaviour_;
    // Due to the auto_ptr, the default copy and assignment operators are
    // dangerous.  You could use a smart pointer or implement 
    // these by having a clone() function in the behaviour class.
    // Therefore copy/assign are private to prevent accidental misuse.
    Player(Player const&);
    Player& operator=(Player const&);
}; 
Animal -> Fliers -> Bird -> Merlin
       -> Runners -> Rodent -> Gerbil