C++ 从已初始化的父类创建子类
C++ Creating Child Class from a Parent Class that's already been initialised
我有一个类"Player"。它的成员是简单的字符串和整型我为每一个都有getter和setter。基本的东西:(有很多成员,所以我只给了3来收缩代码):
PLAYER.H
class Player
{
private:
string Name;
string Role;
int FFDefence;
......etc
public:
//constructor function
Player(
string Name = "Not Stated",
string vRole = "Not Stated",
int vFFDefence = 0,
......etc
)
//Getter Functions
string GetName() const;
string GetRole() const;
int GetFFDefence() const;
.....etc
//Setter Functions
void SetName (string x);
void SetRole(string x);
void SetFFDefence(int x);
......etc
};
PLAYER.CPP
Player::Player( string vName,
string vRole,
int vFFDefence,
......etc
{
Name = vName;
Role = vRole;
FFDefence = vFFDefence,
......etc
}
//getter functions
string Player::GetName() const {return Name; };
string Player::GetRole() const {return Role; };
int Player::GetFFDefence() const {return FFDefence; };
.....etc
//Setter Functions
void Player::SetName(string x) { Name = x ; };
void Player::SetRole(string x) { Role = x ; };
void Player::SetFFDefence(int x) { FFDefence = x ; };
......etc
所以是的-相当标准的......现在我有了第二个类,其中一个成员函数是Player类本身。
BATTER.H
class Batter
{
private:
Player ID;
int Touch;
....etc
public:
Batter(Player vID, int vTouch = 0....etc);
//Getter Functions
string GetRole() const;
int GetFFDefence() const;
int GetBFDefence() const;....and so on.
好的-这是代码的方式!!!!
所以我已经让它做了我想要的一切在传递变量方面....所以我可以创建
Player Dave ("Dave", "Opener", 98, ....etc)
然后(当我需要它的时候)创建
Batter OnStrike (Dave, 10, .....etc)
所有肉汤……我开始研究继承并意识到这是我应该做的....反向转换不是问题(前几天对数组和向量进行了此操作)…
我的问题是:
有了我现在得到的,我可以创建"Player Dave",然后在我需要的时候将他传递给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
是否是您的情况下的正确工具。你将一个Player
对象传递给建筑的事实暗示了这样一个事实,即玩家可能会变成击球手,之后也可能不再是击球手。也就是说,Batter
实际上是玩家可能暂时拥有的角色。因此,将Player
对象与角色分开可能是一个更好的主意,通过拥有单独的Role
层次结构,其中Batter
和Pitcher
派生自Role
, 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)
{
...
但是你的实现最终取决于你自己。
您在这里做的是聚合,而不是继承。击球手有一个球员。继承将是一个击球手,一个球员。
你的设计很好,你不想为这个做继承。
在这种情况下,从概念的角度来看,击球手总是一个球员是可以接受的,但当你与击球手打交道时,球员所描述的大部分内容都是无关的,当你以球员的身份处理他们时,他们可能没有击球。
棒球对我来说有点陌生,但如果你沿着继承路线走下去,你会有球员的后代为球队中的每个角色,当你的投手出来击球时,你会陷入困境。
继承路径的经典示例。
Animal -> Fliers -> Bird -> Merlin
-> Runners -> Rodent -> Gerbil
你把蝙蝠和鸵鸟放在哪里?
你只剩下说蝙蝠是鸟,发明了一个新的类飞行啮齿动物,或者啮齿动物有两个父母……
所有这些都将导致一个令人困惑的bug测试。
以极度怀疑的态度查看所有无意识的继承之锤。
这实际上取决于您希望如何分解代码。一个给定的Player
会变成Batter
以外的任何东西吗?如果可以,那么可能最好使用聚合(以类似于您现在所做的方式)。
如果你正在聚合,那么可能使用另一个类来保存数据。你可以有一个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
做一些不同的事情。
Player
就永远不会被直接实例化,而总是需要派生。我建议阅读Scott Meyers的《更有效的c++》来理解为什么会这样。里面有一节专门讲这个。事实上,继承和OO设计的一些细节在这里得到了很好的解释。
你可能真正想要的是一些稍微不同的东西,这取决于你预期你的模型改变的地方,另外,你需要它有动态行为可能通过使用虚函数?
你可以有一个Player
类,有你所有的球员特定的细节。然后你可以有一个PlayerBehaviour
类来实现播放器的功能:
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&);
};
因此,从Player
继承Batter
将情况建模为Batter
is-a Player
。有一个Behaviour
模型的情况下,Player
有一个Behaviour
,如Batter
.
停止使用"父"answers"子"的术语,想想"基"类和"派生"类…其他人都这么叫他们。"Parent"answers"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
和Derived
对象(一个在另一个里面),这可能是你想要的。
如果你有一个已经存在的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
放在Derived
对象中,相反,它通过调用Base
复制构造函数使基对象成为b
对象的副本,所以现在有两个Base
对象,原始的b
和d
中的一个。这更接近原始代码,其中Batter
包含Player
成员,但现在它是一个基类而不是成员。
如果你想使用继承,第一种形式可能更合适,你传递参数到派生类,它使用这些参数创建基类。
- 在全局变量中保存类的实例以重新创建类(创建"backup")
- 从类继承时,继承的类是否会通过父类重新定义继承的变量
- 从父类方法返回子类对象
- c++, 在子类中,如何在没有对象的情况下访问父类的方法?
- 将父类对象强制转换为子类的问题
- 在C++中为链表类创建实例
- 在运行时选择父类的实现
- 如何在C++子类中访问父类的私有变量
- 将父类的子类的数据复制到具有相同父类的另一个类
- 在父类函数中创建子类 - 可能吗?
- 如何从继承的父类创建unique_ptr
- 如何仅通过父类对象限制对象创建
- 在 C++ 的父类中创建派生的 CARS
- 如果成员对象是父类的一部分,则无法创建成员对象
- C++:在父类中创建子类时出现问题
- 如何使用在子构造函数中创建的对象构造父类
- 如何在不把内部类的定义放入父类的情况下创建一个内部类
- 如何在继承类中创建父类变量数组作为私有成员
- C++ 从已初始化的父类创建子类
- c++虚方法:必须在父类中为父类和子类不共享的每个方法创建一个虚方法吗?