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