سؤال

لدي فئة (الفئة أ) تم تصميمها لكي ترثها فئات أخرى كتبها أشخاص آخرون.لدي أيضًا فئة أخرى (الفئة ب)، والتي ترث أيضًا من أ.

يجب على B الوصول إلى بعض وظائف أعضاء A التي لا ينبغي الوصول إليها بواسطة الفئات الموروثة الأخرى.

لذلك، يجب أن تكون وظائف أعضاء المجموعة "أ" عامة بالنسبة لـ "ب"، ولكنها خاصة للآخرين.

كيف يمكنني حلها دون استخدام توجيه "الصديق"؟

شكرًا لك.

يحرر:مثال لماذا أنا في حاجة إليها.

class A
{
public:
  void PublicFunc()
  {
    PrivateFunc();
    // and other code
  }
private:
  virtual void PrivateFunc();
};

class B : public class A
{
private:
  virtual void PrivateFunc()
  {
    //do something and call A's PrivateFunc
    A::PrivateFunc(); // Can't, it's private!
  }
};
هل كانت مفيدة؟

المحلول

ما تقوله هو: هناك مجموعتين من الفئات الفرعية من A. يجب أن يكون مجموعة واحدة الوصول، لا ينبغي أن مجموعة أخرى. تشعر أنها خاطئة لديها واحدة فقط العلامة التجارية من الفئات الفرعية (أي B) 'رؤية أفراد أ.

إذا كنت تقصدين: فقط <م> نحن يمكن استخدام <م> هذه جزء من وظيفة، في حين يمكن لعملائنا لا، هناك منتجعات أخرى

.

(وظيفة إعادة بالميراث في كثير من الأحيان زوايا لكم مع هذا النوع من المشاكل. إذا ذهبت نحو إعادة استخدامها من قبل التجميع، قد تحصل من حوله).

واقتراح:

// separate the 'invisible' from the 'visible'.
class A_private_part {
protected: 
  int inherited_content();
public:
  int public_interface();          
};

class B_internal : public A_private_part {
};

class A_export : private A_private_part {
public:
    int public_interface() { A_private_part::public_interface(); }
};

// client code
class ClientClass : public A_export {
};

ولكن سيكون من الأفضل أن تمضي في طريقك التجميع، وتقسيم "A" الحالي إلى مرئية وجزءا غير مرئي:

class InvisibleFunctionality {
};

class VisibleFunctionality {
};

class B {
    InvisibleFunctionality m_Invisible;
    VisibleFunctionality m_Visible;
};

// client code uses VisibleFunctionality only
class ClientClass {
    VisibleFunctionality m_Visible;
};

نصائح أخرى

وأنت لا تستطيع ذلك. هذا ما هو صديق لل.

وبديل سيكون لتغيير تصميم / الهندسة المعمارية البرنامج. ولكن للحصول على تلميحات حول هذا كنت بحاجة الى المزيد من السياق.

حسنًا - إذا كنت تريد بالضبط ما وصفته، إذن صديق هو الحل الأفضل.يوصي كل معيار ترميز بعدم استخدامه صديق ولكن عندما يكون التصميم البديل أكثر تعقيدًا - فربما يكون الأمر يستحق إجراء استثناء.

لحل المشكلة بدون صديق سوف يتطلب بنية مختلفة

قد يكون أحد الحلول هو استخدام نموذج من لغة pImpl حيث يتم اشتقاق "B" من كائن التنفيذ الداخلي، بينما يتم اشتقاق العملاء الآخرين من الفئة الخارجية.

قد يكون الحل الآخر هو وضع طبقة إضافية من الميراث بين "أ" و"العملاء الآخرين".شيء مثل:

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

class B : public A {  // OK access to both 'foo' and 'bar'
};

class ARestricted : private A {
public:
  inline void foo () { A::foo (); };    // Forwards 'foo' only
};

ومع ذلك، لا يزال هذا الحل يعاني من مشاكله.لا يمكن تحويل "ARestricted" إلى "A" لذا يجب حل هذه المشكلة بواسطة "أداة" أخرى لـ "A".ومع ذلك، يمكنك تسمية هذه الوظيفة بطريقة لا يمكن استدعاؤها عن طريق الخطأ:

  inline A & get_base_type_A_for_interface_usage_only () { return *this; }

بعد محاولة التفكير في حلول أخرى، وافتراض أن التسلسل الهرمي الخاص بك يجب أن يكون كما وصفته، أوصيك فقط باستخدام صديق!

يحرر: لذا com.xtofl اقترح إعادة تسمية النوعين "A" إلى "AInternal" و"ARestricted" إلى "A".

لقد نجح هذا الأمر، إلا أنني لاحظت أن "B" لن يكون "A" بعد الآن.ومع ذلك، يمكن وراثة AInternal افتراضيًا - ومن ثم يمكن اشتقاق "B" من كل من "AInternal" و"A"!

class AInternal {
public:
  void foo ();
  void bar ();
};

class A : private virtual AInternal {
public:
  inline void foo () { A::foo (); };    // Forwards 'foo' only
};

// OK access to both 'foo' and 'bar' via AInternal
class B : public virtual AInternal, public A {
public:
  void useMembers ()
  {
    AInternal::foo ();
    AInternal::bar ();
  }
};

void func (A const &);

int main ()
{
  A a;
  func (a);

  B b;
  func (b);
}

بالطبع الآن لديك قواعد افتراضية وميراث متعدد!هممم.... الآن، هل هذا أفضل أم أسوأ من أغنية واحدة صديق تصريح؟

واعتقد ان لديك مشكلة أكبر هنا. التصميم الخاص بك لا يبدو الصوت.

1) وأعتقد بناء على "صديق" مثير للجدل لتبدأ

2) إذا 'صديق' ليس ما تريد، تحتاج إلى إعادة النظر في التصميم الخاص بك.

وأعتقد أنك تحتاج إما أن تفعل شيئا أن يحصل فقط على هذه المهمة، وذلك باستخدام "صديق" أو تطوير بنية أكثر قوة. نلقي نظرة على بعض <لأ href = "http://www.tml.tkk.fi /~pnr/Tik-76.278/gof/html/ "يختلط =" نوفولو noreferrer "> أنماط التصميم ، وأنا متأكد من أنك سوف تجد شيئا مفيدا.

وتحرير:

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

public Class B
{
    B() 
    {

    }

    void someFunc()
    {
       A a; //the private functions is now called and a will be deleted when it goes out of scope
    }

};

وأجد أن هذا تحديا مثيرا للاهتمام. هنا هو كيف سيكون حل المشكلة:

class AProtectedInterface
{
public:
    int m_pi1;
};

class B;
class A : private AProtectedInterface
{
public:
    void GetAProtectedInterface(B& b_class);

    int m_p1;
};

class B : public A
{
public:
    B();
    void SetAProtectedInterface(::AProtectedInterface& interface);

private:
    ::AProtectedInterface* m_AProtectedInterface;
};

class C : public A
{
public:
    C();
};

C::C()
{
    m_p1 = 0;
//    m_pi1 = 0; // not accessible error
}

B::B()
{
    GetAProtectedInterface(*this);

    // use m_AProtectedInterface to get to restricted areas of A
    m_p1 = 0;
    m_AProtectedInterface->m_pi1 = 0;
}

void A::GetAProtectedInterface(B& b_class)
{
    b_class.SetAProtectedInterface(*this);
}

void B::SetAProtectedInterface(::AProtectedInterface& interface)
{
    m_AProtectedInterface = &interface;
}

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

template<class T, class I>
class ProtectedInterfaceAccess : public I
{
public:
    void SetProtectedInterface(T& protected_interface)
    {
        m_ProtectedInterface = &protected_interface;
    }

protected:
    T& GetProtectedInterface()
    {
        return *m_ProtectedInterface;
    }

private:
    T* m_ProtectedInterface;
};

template<class T, class I>
class ProtectedInterface : private T
{
public:
    void SetupProtectedInterface(I& access_class)
    {
        access_class.SetProtectedInterface(*this);
    }
};

class Bt;
class At : public ProtectedInterface <::AProtectedInterface, Bt>
{
public:
    int m_p1;
};

class Bt : public ProtectedInterfaceAccess<::AProtectedInterface, At>
{
public:
    Bt();
};

class Ct : public At
{
public:
    Ct();
};

Ct::Ct()
{
    m_p1 = 0;
    // m_pi1 = 0; // not accessible error
}

Bt::Bt()
{
    SetupProtectedInterface(*this);

    m_p1 = 0;
    GetProtectedInterface().m_pi1 = 0;
}

إذا فهمت:

  • سيتم تصنيف A بواسطة مطورين آخرين.
  • سيتم تصنيف B ضمن فئة فرعية بواسطة مطورين آخرين ويرثون من A.
  • يحتوي "أ" على بعض الأساليب التي لا تريد أن يصل إليها المطورون الخارجيون من خلال "ب".

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

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