سؤال

دعونا نقول لدي التالية البنية الطبقية:

class Car;
class FooCar : public Car;
class BarCar : public Car;

class Engine;
class FooEngine : public Engine;
class BarEngine : public Engine;

دعونا أيضا إعطاء Car مقبض لها Engine.A FooCar سيتم إنشاؤها مع FooEngine* و BarCar سيتم إنشاؤها مع BarEngine*.هل هناك طريقة لترتيب الأمور لذلك FooCar الكائن يمكن استدعاء وظائف الأعضاء من FooEngine دون downcasting?

هنا لماذا بنية الطبقة وضعت على ما هو عليه الآن:

  1. كل Cars لديك Engine.وعلاوة على ذلك ، FooCar فقط من أي وقت مضى استخدام FooEngine.
  2. هناك بيانات و خوارزميات مشتركة من قبل جميع Engines أنني أفضل عدم نسخ ولصق.
  3. قد ترغب في كتابة وظيفة يتطلب Engine أن تعرف عن Car.

في أقرب وقت كما كنت كتبته dynamic_cast عند كتابة هذا الرمز ، أنا أعرف ربما كنت تفعل شيئا خاطئا.هل هناك طريقة أفضل للقيام بذلك ؟

تحديث:

استنادا إلى الإجابات التي أعطيت حتى الآن, أنا أميل نحو احتمالين:

  1. لديك Car تقدم ظاهري getEngine() وظيفة.التي من شأنها أن تسمح FooCar و BarCar أن يكون التنفيذ التي ترجع النوع الصحيح من Engine.
  2. استيعاب جميع Engine وظائف في Car الميراث شجرة. Engine كان اندلعت لأسباب الصيانة (للحفاظ على Engine الأشياء في مكان منفصل).هو المفاضلة بين أكثر الفئات الصغيرة (الصغيرة في الأسطر من التعليمات البرمجية) مقابل وجود عدد أقل من الطبقات الكبرى.

هل هناك مجتمع قوي تفضيل واحد من هذه الحلول ؟ هل هناك خيار ثالث لم يعتبر ؟

هل كانت مفيدة؟

المحلول

أنا على افتراض أن السيارة تحمل محرك المؤشر ، وهذا هو السبب في أنك تجد نفسك downcasting.

يأخذ المؤشر من الفئة الأساسية واستبدالها ظاهري get_engine() وظيفة.ثم FooCar و BarCar يمكن أن تعقد مؤشرات الصحيح نوع المحرك.

(تحرير)

لماذا يعمل هذا:

منذ الظاهري وظيفة Car::get_engine() سيعود المرجعي أو مؤشر, C++ سوف تسمح الفئات المشتقة لتنفيذ هذه الوظيفة مع مختلفة نوع الإرجاع, طالما عودة نوع يختلف فقط من خلال كونها أكثر نوع مشتق.

وهذا ما يسمى أنواع الإرجاع طردي, و تسمح كل Car نوع من العودة الصحيحة Engine.

نصائح أخرى

شيء واحد فقط أريد أن أضيف:هذا التصميم بالفعل رائحة سيئة بالنسبة لي بسبب ما أسميه موازية الأشجار.

أساسا إذا كنت في نهاية المطاف مع موازية الطبقة الهرمية (لديك مع السيارة و المحرك) ثم أنت فقط يسأل عن المتاعب.

وأود أن إعادة النظر إذا كان المحرك (و حتى سيارة) يحتاج إلى الفئات الفرعية أو تلك كلها مجرد حالات مختلفة من نفس كل فئات أساسية.

هل يمكن أيضا templatize نوع المحرك على النحو التالي

template<class EngineType>
class Car
{
    protected:
        EngineType* getEngine() {return pEngine;}
    private:
        EngineType* pEngine;
};

class FooCar : public Car<FooEngine>

class BarCar : public Car<BarEngine>

أنا لا أرى لماذا السيارة لا يمكن أن تكون مؤلفة من محرك (إذا BarCar دائما تحتوي على BarEngine).المحرك قوي جدا العلاقة مع السيارة.وأود أن تفضل:

class BarCar:public Car
{
   //.....
   private:
     BarEngine engine;
}

سيكون من الممكن بالنسبة FooCar استخدام BarEngine?

إن لم يكن, قد ترغب في استخدام AbstractFactory لخلق الكائن السيارة مع المحرك.

يمكنك تخزين FooEngine في FooCar, BarEngine في BarCar

class Car {
public:
  ...
  virtual Engine* getEngine() = 0;
  // maybe add const-variant
};

class FooCar : public Car
{
  FooEngine* engine;
public:
  FooCar(FooEngine* e) : engine(e) {}
  FooEngine* getEngine() { return engine; }
};

// BarCar similarly

المشكلة مع هذا النهج هو أن الحصول على محرك مكالمة الظاهري (إذا كنت قلقا حول ذلك) ، وطريقة الإعداد المحرك في Car يتطلب downcasting.

أعتقد أن ذلك يعتمد إذا Engine هو فقط من القطاع الخاص تستخدم من قبل Car و الأطفال أو إذا كنت ترغب في استخدامه في أشياء أخرى.

إذا Engine وظائف غير محددة Cars, وأود أن استخدام virtual Engine* getEngine() الطريقة بدلا من الحفاظ على المؤشر في الفئة الأساسية.

إذا كان المنطق غير محددة Cars, يفضل وضع المشترك Engine البيانات/المنطق في كائن منفصل (ليس بالضرورة متعدد الأشكال) والحفاظ على FooEngine و BarEngine التنفيذ في كل منهما Car الطفل الطبقة.

عند تنفيذ إعادة التدوير هو أكثر حاجة من واجهة الميراث ، تكوين الكائن في كثير من الأحيان توفر قدرا أكبر من المرونة.

مايكروسوفت كوم هو نوع من عالي الكعب ، ولكن لديها مفهوم جديد - إذا كان لديك مؤشر إلى واجهة كائن ، يمكنك الاستعلام لمعرفة ما إذا كان يدعم أي الواجهات الأخرى باستخدام QueryInterface وظيفة.الفكرة هي كسر الخاص بك محرك فئة في واجهات متعددة حتى أن بعضها يمكن استخدامها بشكل مستقل.

مما لم أفوت شيئا ، وهذا ينبغي أن تكون تافهة.

أفضل طريقة للقيام بذلك هو خلق نقية وظائف افتراضية في المحرك ، ثم المطلوبة في الفئات المشتقة التي يتم إنشاء مثيل.

رصيد إضافي الحل ربما يكون واجهة تسمى IEngine, التي بدلا من passs إلى سيارتك ، وكل وظيفة في IEngine هو محض افتراضية.هل يمكن أن يكون 'BaseEngine' التي تطبق بعض الوظائف التي تريدها (أي 'المشتركة') ومن ثم يكون ورقة منها الخروج من ذلك.

واجهة جميلة هل لديك شيء تريد أن مثل محرك, ولكن ربما ليس (أي تجارب وهمية فصول هذه).

هل هناك طريقة لترتيب الأمور حتى FooCar كائن يمكن استدعاء وظائف الأعضاء من FooEngine دون downcasting?

مثل هذا:

class Car
{
  Engine* m_engine;
protected:
  Car(Engine* engine)
  : m_engine(engine)
  {}
};

class FooCar : public Car
{
  FooEngine* m_fooEngine;
public:
  FooCar(FooEngine* fooEngine)
  : base(fooEngine)
  , m_fooEngine(fooEngine)
  {}
};
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top