سؤال

لدي مشكلة أعتقد أنها ذات صلة إلى الأمام الإعلانات ، ولكن ربما لا.

هنا هو رمز ذات الصلة:

A. h

#ifndef A_H_
#define A_H_

#include "B.h"

class A
{
    private:
        B b;

    public:
        A() : b(*this) {}

        void bar() {}
};

#endif /*A_H_*/

B. h

#ifndef B_H_
#define B_H_

#include "A.h"

class A;

class B
{
    private:
        A& a;

    public:
        B(A& a) : a(a) {}

        void foo() { /*a.bar();*/ } //doesn't compile
};

#endif /*B_H_*/

main.cpp

#include "A.h"

int main()
{
    A a;

    return 0;
}

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

خطأ:صالح استخدام نوع غير مكتملة 'البنية أ'

خطأ:إلى الأمام إعلان 'البنية أ'

أفترض هذا هو::شريط() لم يتم تعريف أو أعلن لأن كلا رؤوس مرجع بعضها البعض.إلا أنني إلى الأمام أعلن فئة A و أنا في حيرة ماذا يجب أن أفعل.أنا جديد في C++, لذا يرجى أن يغفر لي.أنا لا يمكن العثور على الإجابة على هذا السؤال في أي مكان آخر على الإنترنت.كما هو الحال دائما, شكرا مقدما!

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

المحلول

وكنت قد حصلت على مرجع معاد، لذلك تحتاج إلى فصل B.h. جرب شيئا مثل:

وB.h:

#ifndef B_H_
#define B_H_

// don't include A.h here!

class A;

class B
{
   private:
      A& a;

   public:
      B(A& a) : a(a) {}

      void foo();
};

#endif /*B_H_*/

وB.cpp:

#include "B.h"
#include "A.h"

void B::foo() { a.bar(); } // now you're ok

وتحرير: تفسير لماذا تحتاج إلى تقسيمه إلى ملفين:

ووB الطبقة تحتوي على مرجع إلى A، التي يمكن أن تكون ما يسمى ب <م> ناقصة نوع. لا يمكنك استدعاء أي وظائف عليها، لأن المترجم لا نعرف حتى الآن ما هو A هيك - أنه يعلم تماما أنه من فئة من نوع ما. مرة واحدة قمت بتضمين A.h (في الملف .cpp)، ثم A هو نوع كاملة، ويمكنك أن تفعل ما تريد مع ذلك.

وأنت لا يمكن أن تبقي على كل شيء في ملف واحد رأس لأنك سوف تحصل على مرجع معاد. كنت منع حلقة لا نهائية مع الخاص تشمل الحراس، ولكن كنت الحصول على شيء كنت لا تريد. انظروا الى ما ينتهي المترجم مع عند ترجمة MAIN.CPP، كما كان لديك من قبل:

// #include "A.h" ==>
#define A_H_

// #include "B.h" ==>
#define B_H_

// #include "A.h" ==> nothing happens! (since A_H_ is already defined)

class A;

class B {
private:
    A& a;

public:
    B(A& a) : a(a) {}

    void foo() { a.bar(); } // <-- what the heck is A here?
                            //     it's not defined until below
};

class A {
private:
   B b;

public:
   A() : b(*this) {}

   void bar() {}
};

int main() {
    A a;
    return 0;
}

نصائح أخرى

وو#include<file.h> خط سيحل محل فقط تماشيا مع مضمون file.h. حتى عندما يحاول الكمبيوتر لتجميع main.cpp الخاص بك، فإنه سيتم سحب كل شيء معا، والتي تبدو كما يلي. في المكان الذي تريد استخدام شريط :: ()، لم يتم تعريفه.

// result from #include "A.h"

#ifndef A_H_
#define A_H_

// Now, #include "B.h" in A.h will get you the following
#ifndef B_H_
#define B_H_

// here you include "A.h" again, but now it has no effect
// since A_H_ is already defined

class A;

class B
{
    private:
            A& a;
    public:
            B(A& a) : a(a) {}
            // Oops, you want to use a.bar() but it is not defined yet
            void foo() { /*a.bar();*/ } 
};

#endif /*B_H_*/

class A
{
    private:
            B b;
    public:
            A() : b(*this) {}
            void bar() {}
};
#endif /*A_H_*/

// now this is your main function
int main()
{
    A a;
    return 0;
}

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

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

دعونا نقول لدينا فئتين:البيانات DataAnalyzer

بيانات يحمل إشارة إلى DataAnalyzer (تستخدم لتحليل البيانات) ، DataAnalyzer يحمل إشارة إلى البيانات (البيانات المراد تحليلها) -- التبعية المتبادلة!من أجل القضاء على هذه التبعية ، ونحن استخراج واجهة (في C++, نقية الطبقة الظاهرية) من DataAnalyzer أن يعرف الأساليب العامة/سمات المطلوبة على DataAnalyzer.قد تبدو شيئا مثل:

class IAnalyzer
{
public:
    virtual void Analyze () = 0;
};

عندما نحدد DataAnalyzer ، ونحن نفعل ذلك على النحو التالي:

class DataAnalyzer : public IAnalyzer
{
public:
    DataAnalyzer (Data* data);

    virtual void Analyze (); // defined in DataAnalyzer.cpp
};

والبيانات تبدو مثل:

class Data
{
public:
    Data ();

    IAnalyzer* Analyzer;
};

في مكان ما في جهاز تحكم الدرجة, قد يكون لديك شيء من هذا القبيل:

void main ()
{
    Data*  data = new Data ();
    data->Analyzer = new DataAnalyzer (data);
}

الآن البيانات تقف في حد ذاته (بقدر ما يعرف ، IAnalyzer لا تتطلب إشارة إلى البيانات) فقط DataAnalyzer تعتمد على البيانات.إذا كنت ترغب في الاستمرار ، يمكن أن تستمر في إزالة DataAnalyzer هو الاعتماد على البيانات ، ولكن من أجل ببساطة كسر التبعية المتبادلة ، وهذا ينبغي أن يكون كافيا.

تحذير: لم تجميع اختبار هذا القانون ، لذلك قد تتطلب بعض التعديل البسيط إلى تجميع وتشغيل بشكل صحيح.

حظا سعيدا!

إذا كنت تريد حقا B :: فو أن تكون مضمنة يمكن أن تفعله تنفيذ في B.h، على الرغم من أنني لن أوصي به.

وB.h:

#ifndef B_H_
#define B_H_

// Forward declaration of A.
class A;

class B
{
private:
    A& a;

public:
    B(A& a) : a(a) {}

    void foo();
};

// Include definition of A after definition of B.
#include "A.h"

inline void B::foo()
{
    a.bar();
}

#endif /*B_H_*/

وA.h:

// Include definition of B before definition of A.
// This must be done before the ifndef A_H_ include sentry,
// otherwise A.h cannot be included without including A.h first.
#include "B.h"

#ifndef A_H_
#define A_H_

class A
{
private:
    B b;

public:
    A() : b(*this) {}

    void bar() {}
};

#endif /*A_H_*/

في B.h، وأنت بما في ذلك A.h وكذلك إعلان قدما A.

وتحتاج إلى فصل B.h إلى B.h وB.cpp، أو إزالة الإعلان إلى الأمام.

وأيضا لدينا PS أنت تبعية دائرية. A.h هو بما في ذلك B.h، والعكس بالعكس. حراس بك هي اللحاق المشكلة، على الرغم؛)

لإضافة إلى الإجابة الأخرى (مرجع معاد، وهو الجواب الصحيح)، إذا كنت قادما من C # / جافا، نفهم أن C ++ يختلف، في يتم تحليل تلك الملفات في النظام (بدلا من النظر فيها ككل ). لذلك عليك أن تكون حذرا للتأكد من أن يعرف كل شيء قبل استخدامها، في الترتيب الفعلي التي تم تضمينها الملفات (و / أو وظيفة منفصلة في ملفات .CPP حسب الاقتضاء).

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