3

クラス「プレーヤー」があります。そのメンバーは単純な文字列と整数であり、これらのそれぞれにゲッターとセッターがあります...基本的なもの: (メンバーがたくさんあるので、コードを縮小するために 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

そうそう-かなり標準的なものです...今、私はメンバー関数の1つがプレーヤークラス自体である2番目のクラスを持っています。

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.

OK - それは邪魔にならないコードです!!!!

だから私は変数を出し入れするという点で私が望むすべてをやらせました....だから私は作成することができます

Player Dave ("Dave", "Opener", 98, ....etc)

その後(必要なときに)作成します

Batter OnStrike (Dave, 10, .....etc)

すべての肉汁....OKなので、継承を調べ始めて、これが私がすべきことだと気づきました....逆変換は問題ではありません(先日、配列とベクトルでこれを行いました)...

これが私の問題です:

私が今持っているもので、私は「Player Dave」を作成し、必要なときにいつでも彼を Batter のサブクラスに渡すことができます。従来の継承で同じことを行うにはどうすればよいですか? Player の特定のインスタンス (作成済み) を取得し、それを子クラス Batter の特定のインスタンスの親として使用するにはどうすればよいですか? 現時点で推測できる限り、両方を同時に作成する必要があります。

4

5 に答える 5

3

提供されたオブジェクトでベースオブジェクトを初期化するだけです:

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

class Batter:
  public Player
{
  Batter(Player const& p, other arguments):
    Player(p),
    ...
  {
    ...
  }
};

一方、Batterfromの継承がPlayerあなたの場合に適切なツールであるかどうかという問題があります。Playerオブジェクトをコンストラクションに渡すという事実は、プレーヤーが打者になる可能性があり、後で打者でなくなる可能性があることを暗示しています。つまり、Batter実際にはプレーヤーが一時的に持つことができる役割です。したがって、とから派生する別の階層を持ち、現在のロールを返すメソッドと、プレーヤーに別のロールを割り当てることができる別のメソッドをPlayer持つことにより、オブジェクトをロールから分離することをお勧めします。RoleBatterPitcherRolePlayer

于 2013-06-18T22:05:33.587 に答える
0

コードを実際にどのようにファクタリングしたいかによって異なります。与えられ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初期化します。

コードで何を表現しようとしているのかをよく考えてください。

Batter派生したい理由は、で実装されているPlayer仮想関数が必要であり、それが aまたは aであるかどうかに応じて異なることを行う場合です。PlayerBatterPlayerBatter

余談ですが、可能であれば基本クラスを抽象化するのが最善です。そのため、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&);
}; 

Batterそのため、モデルからPlayer状況をBatteris-aとして継承しPlayerます。a を持つことは、 aなどのhas-aBehaviourとして状況をモデル化します。PlayerBehaviourBatter

于 2013-06-18T22:36:50.820 に答える
0

ここでは、継承ではなく集約を行っています。バッターにはプレーヤーがいます。継承は打者が選手だろう。

あなたのデザインは良いです、あなたはこれを継承したくありません。

この場合、概念的な観点からバッターは常にプレーヤーであると言っても問題ありませんが、バッターを扱っている場合、プレーヤーが説明することの多くは無関係であり、プレーヤーとして扱う場合、彼らはバッティングしていない可能性があります.

野球は私には少しなじみがありませんが、継承ルートをたどると、チーム内の役割ごとにプレーヤーの子孫があり、投手が打席に出たときに適切な混乱が発生します。

継承ルートの古典的なイラスト。

Animal -> Fliers -> Bird -> Merlin
       -> Runners -> Rodent -> Gerbil

コウモリとダチョウはどこに置く?

コウモリは鳥だと言ったり、FlyingRodent という新しいクラスを発明したり、両親が 2 人いるげっ歯類を作ったりするしかありません...

これらはすべて、紛らわしいバグ祭りにつながります。

極度の疑いを持って継承ハンマーの無意識のリーチをすべて表示します。

于 2013-06-18T22:43:25.757 に答える
-1

「親」と「子」という用語の使用をやめて、「基本」クラスと「派生」クラスについて考えてください...それは他の誰もがそれらを呼んでいるものです. 「親」と「子」は、他の多くの方法 (たとえば、別のオブジェクトを所有するオブジェクト) で使用できるため、継承関係について話している場合、用語が混乱します。

派生クラスには、それ自体の内部に基本型のインスタンス全体が含まれています。派生コンストラクターが実行を開始すると、最初にすべてのベースを構築します。これは、コンストラクターを呼び出すことによって行われます。したがって、派生クラスは、適切な引数を渡すことにより、ベースの構築方法を制御できます。

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);

これにより、BaseDerivedオブジェクトの両方が同時に (一方が他方の中に) 作成されますが、これはおそらくあなたが望むものです。

既存の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ことによって、ベース オブジェクトをオブジェクトのコピーにします。そのため、元のオブジェクトと内部のオブジェクトの 2 つのオブジェクトが存在します。これは元のコードに近く、メンバーが含まれていますが、現在はメンバーではなく基本クラスです。bBaseBasebdBatterPlayer

継承を使用したい場合は、派生クラスに引数を渡し、それらの引数を使用してベースを作成する最初の形式がおそらくより適切です。

于 2013-06-18T22:05:43.063 に答える