سؤال

أحاول التغليف بشكل صحيح فئة أ، والتي يجب تشغيلها فقط حسب الفئة B.

ومع ذلك، أريد أن يرث من الفصل B.

وجود صديق B لا يعمل - لا تورث الصداقة.

ما هي الطريقة المقبولة عموما لإنجاز ما أريد، أو هل ارتكب خطأ؟

لتعطيك لون أكثر قليلا، يمثل الفئة A حالة نظام معقدة. يجب تعديلها فقط من قبل B، وهي الإجراءات التي يمكن تطبيقها لتغيير حالة الفئة A.

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

المحلول

أفترض أنك تريد السماح بأحفاد B للوصول مباشرة؟ إذا كانت A و B مقارنة بإحكام، فيمكنك إنشاء تعريف فئة محمية داخل B في حد ذاته، بدلا من كونها تعريفا مستقلا. على سبيل المثال

class B
{
protected:
    class A
    {
    };
};

فكرة أخرى هي إنشاء أساليب محمية على B التي تفوض أفعالها إلى AEG

class A
{
friend class B;
private:
    void DoSomething();
};

class B
{
protected:
    void DoSomething(A& a) { a.DoSomething(); }
};

نصائح أخرى

يبدو أنك قد تحتاج إلى إعادة تصميم؛ يمثل الفصل الدراسي الخاص بك حالة، لكن صفك B يمثل مجموعة من الإجراءات. هناك علاقة هناك، لكنها ليست علاقة الميراث. أود أن أقترح تكوين؛ تريد المزيد من علاقة الحصص من علاقة ISA، بقدر ما أستطيع أن أقول.

إذا فهمت لك بشكل صحيح، فأنت تريد أن يكون ب ومشتقاتها للحصول على إمكانية الوصول إلى التنفيذ الداخلي للفئة A، نعم؟

لسوء الحظ، ليس لدى C ++ مفهوم مستويات الحماية "الداخلية" تلك اللغات مثل C # و Java تمتلكها.

يمكنك التفكير في استخدام التنفيذ الخاص النموذج (Pimpl) - المعروف أيضا باسم المؤشرات المعتمة، لفضح الوظيفة داخل نظامك باستخدام مستويات الوصول العام، فإن المستهلكين من A و B لن يرون.

مع الحفاظ على كل شيء كما هو الحال، فإن أسهل شيء يجب القيام به هو إضافة أساليب محمية إلى B التي تمنح الوصول إلى الميزة المكافئة ل A التي ستحتاج إليها. هذا يفتح التغليف فقط فرعية من ب.

الطريقة الأكثر وضوحا للقيام بذلك هي ببساطة تحتوي على B تحتوي على A:

الفئة ب {محمية: A_؛ }

بعد ذلك، يمكنك كتابة فئة C التي ترث من B وقادرة على التلاعب A. إذا كان يجب ألا يكون C قادرا على القيام بأشياء تعسفية إلى A، فقم بإجراء عملية خاصة في B وتوفير الأساليب المحمية في B استخدام للقيام بأشياء معتمدة إلى A، مثل ذلك:

فئة ب {خاصة: A_؛ محمية: الفراغ dosomethingtoa ()؛ }

الاحتواء هو الطريق للذهاب (الفئة B تحتوي على عضو خاص في النوع A) ما إذا كان B يحتاج إلى تجاوز بعض المنائعين في أ، في هذه الحالة الميراث الخاص هو أقرب شيء.

لا أستطيع أن أرى لماذا تريد أن ترث. اجعل كل شيء في خاص وصديق B. B ثم لديه عضو في ما يمكن أن يتلاعب بحرية.

الطريقة التي تصفها هذا يبدو أكثر مثل التركيب بدلا من الميراث. على سبيل المثال

class ComplexMachine {
  public:
    setState(int state);
};

class Operator {
   public:
   Operator(ComplexMachine & m) :_m(m) {};

   void drive() { _m->setState(1); }
   void turn() { _m->setState(2); }
   void stop() { _m->setState(0); }

   private:
   ComplexMachine _m;   
};

class SmoothOperator : public Operator { }

العمل مع أجزاء المعلومات التي قدمتها:

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

(من تصميم بوف، حتى لا يحتاج للحصول على موجودة، لكنني واجهت أسباب عملية كافية لمثل هذا الفصل الذي لن أحمله ضدك؛))

قد يتطلب هذا الكثير من رمز الغزل المراد كتابة، أو بعض الخداع مع الواجهة. على سبيل المثال، يجب السماح للعميل باستخدام الفئة A للاستعلام عن معلومات الاستعلام ولكن لا يمكن تعديله، B يمكن أن يدخل CONST وإلى مجمع A. مع برنامج مترجم يدعم __declspec (الخاصية) أو ما شابه ذلك، يمكن تخفيف الألم النحوي.

إذا كنت ترغب في أن تكون متأكدا من أن ب يعمل فقط على A، فقم بإجراء مثيل خاص وفضح واجهة محمية من B إلى أحفادها.

class A
{
  public:
    void foo() {}
};

class B
{
  private:
    A a;

  protected:
    void CallAFoo() { a.foo() };
};

class C : public B
{
    void goo() { CallAFoo(); }
};

من ما أفهمه من سؤالك، ستحتاج إلى بعض تعدد الأشكال. وبعد تحتاج إلى ذلك نبذة مختصرة الفئة A و Class B يرث الفئة A. أيضا، محمي تتيح الكلمة الرئيسية للفصول التي ترث الوصول إلى معلومات معينة بينما تنكر في نفس الوقت الوصول إلى أي شيء آخر. هنا مثال قليلا:

// dynamic allocation and polymorphism
#include <iostream>
using namespace std;

class CPolygon {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      { width=a; height=b; }
    virtual int area (void) =0;
    void printarea (void)
      { cout << this->area() << endl; }
  };

class CRectangle: public CPolygon {
  public:
    int area (void)
      { return (width * height); }
  };

class CTriangle: public CPolygon {
  public:
    int area (void)
      { return (width * height / 2); }
  };

int main () {
  CPolygon * ppoly1 = new CRectangle;
  CPolygon * ppoly2 = new CTriangle;
  ppoly1->set_values (4,5);
  ppoly2->set_values (4,5);
  ppoly1->printarea();
  ppoly2->printarea();
  delete ppoly1;
  delete ppoly2;
  return 0;
}

رمز مأخوذ من cplusplus.com. (يحتوي على معلومات حول تعدد الأشكال والفئات المجردة أيضا).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top