0

C++ を使用する必要があります。C++11 は興味深いですが、ない方がいいと思います。私は次のクラス構造を持っています。

class Wheel { /*...*/ };
class MtbWheel : public Wheel { /*...*/ };

class Bike { Wheel front_wheel; };
class Mountainbike : public Bike { MtbWheel front_wheel; };

これで完全に機能します。Mountainbike は front_wheel をオーバーライドするため、MtbWheel を使用できます。ソフトウェア技術的には、私は満足していません。

  • 私が望むのは、front_wheel のオーバーライドを禁止するか、少なくともクラス Wheel を継承しないクラスによる上書きを制限することです。
  • front_wheel をオーバーライドする代わりに、プロパティを「追加」したいだけです。

編集:仮想関数を使用せずにテンプレートを使用するソリューションはありますか?

4

5 に答える 5

4

クラスの front_wheelメンバーはオーバーライドMountainbike非表示にします。class には実際には 2 つのメンバがありますが、クラスのメンバは で宣言されたメンバによって隠されています。つまり、にアクセスすると 型のオブジェクトにアクセスし、にアクセスすると 型のオブジェクトにアクセスしますが、これら 2 つの wheel オブジェクトはお互いを認識していません! front_wheelMountainbikefront_wheelBikeMountainbikeBikefront_wheelWheelMountainbikefront_wheelMtbWheel

より優れた OO 設計は、front_wheelたとえば にポインターを作成しBike(またはスマート ポインターの方が優れています)、 のコンストラクターで初期化して、 に最適なMountainbike派生クラスのオブジェクトを保持することです。そのようにして、 front_wheel にアクセスするとき、もちろん、いずれかの方法または他の仮想関数が機能します。WheelMountainbike

以下のコメントでの Steve Jessop の提案によると、ポリモーフィズムを使用する代わりにテンプレートを使用する代替ソリューションは次のようになります。

class Wheel { /*...*/ };
class MtbWheel : public Wheel { /*...*/ };

template <typename WheelType>
class Bike { WheelType front_wheel; };

class Mountainbike : public Bike<MtbWheel> { /* ... */ };

そうすれば、front_wheel で操作するときに仮想関数は関与しません。ただし、このようなソリューションには考慮すべき点がいくつかあります。

  • Bike を使用する WheelType ごとに、個別のコードが作成されます。そのようなタイプが多数ある場合、コードが肥大化する可能性があります。
  • Bike異なる WheelType パラメータで派生した複数のクラスがある場合、それらは同じ基本クラスを持たないため (Steve Jessop のコメントとポイント 1 を参照)、ポリモーフィックにアクセスすることもできません。
  • テンプレート パラメータとして Bike に渡されるものに明示的なインターフェイスを強制することはできません。WheelTypeから使用されるメソッドとメンバーによって定義されるのは、暗黙的なインターフェイスのみBikeです。ただし、コンパイラはその暗黙的なインターフェイスを引き続き検証できるため、問題はありません。
于 2012-09-12T11:42:24.123 に答える
1

あなたは何も上書きしていません。Wheel front_wheel;派生クラスにはまだがあります。m.Bike::front_wheel、またはそのようなものからアクセスできます。派生クラスに独自のインスタンス化を提供する場合は、基本クラスにアクセサーをfront_wheel提供するだけで、派生クラスに独自のインスタンスを作成させる必要があります。virtual

于 2012-09-12T11:42:34.543 に答える
1

変数front_wheelはオーバーライドされません-それは単に隠されています。メンバー変数Wheel front_wheelはまだMountainbikeクラスにあります。front_wheelしたがって、実際にはで名前が付けられた2つの変数がありますMountainbike。ただし、の隠れた変数にアクセスするMountainbikeには、明示的に言う必要がありますBike::front_wheel

必要なことを行うためのより良い方法は、データのないインターフェイスクラスを作成することです。

class Bike {
public:
  virtual Wheel const &getFronWheel() const = 0;
  virtual ~Bike() {}
};

そして、そこから特定の自転車を導き出します。

class RegularBike: public Bike {
public:
  virtual Wheel const &getFronWheel() const { return wheel; }
private:
  Wheel wheel;
}

class MtbBike: public Bike {
public:
  virtual MtbWheel const &getFronWheel() const { return wheel; }
private:
  MtbWheel wheel;
}

編集:仮想性を使用せず、代わりにテンプレート:

template<typename WheelType>
class Bike {
public:
  /* Common methods for any bike...*/
protected: // or private
  WheelType wheel;
};

次に、必要に応じてバイクを延長できます。

class RegularBike: public Bike<Wheel> {
   /* Special methods for regular bike...*/
};

class MtbBike: public Bike<MtbWheel> {
   /* Special methods for Mtb bike...*/
};
于 2012-09-12T11:42:48.513 に答える
0

解決策はそれをしないことです。派生クラスを作成するには、基本クラスを注意深く調べてから、注意深く設計する必要がありますマジッククッキーは知識や思考に代わるものではありません。そして、はい、私はこの種の間違いを共有し、不注意であるために自分自身を蹴りました。

于 2012-09-12T12:48:41.373 に答える
0

Class Wheel の代わりに IWheel のインターフェイスを作成できます。

MtbWheel クラスに OverRide メソッドを作成します。このメソッドをオーバーライドしたい人は誰でもこのメソッドをオーバーライドできるように、それ以外の場合は MtbWheel クラスに実装したデフォルトのメソッドを使用します。これを使用すると、そのプロパティを追加できます。

于 2012-09-12T11:45:35.310 に答える