سؤال

وأنا الحصول على أخطاء الربط من النوع التالي:

<اقتباس فقرة>   

وFestival.obj: خطأ LNK2019:   رمز الخارجية لم يتم حلها "العامة:   باطلة __thiscall شجرة :: إضافة (فئة السعر و) "   (؟ إضافة @؟ $ شجرة @ VPrice@@QAEXAAVPrice@Z)   المشار إليها في وظيفة   __catch $؟ AddBand @ مهرجانQAE؟ AW4StatusTypeHHH @ Z $ 0

وكنت أعتقد أنه له علاقة مع آلية محاولة اللحاق، ولكن منذ ذلك الحين قال خلاف ذلك. هذا هو نسخة محدثة من هذه المسألة.

وأنا باستخدام Visual Studio 2008، ولكن لدي مشاكل مماثلة في غرام ++.

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

في Festival.cpp

#include "Tree.h"
#include <exception>

using namespace std;

class Band{
public:
    Band(int bandID, int price, int votes=0): bandID(bandID), price(price), votes(votes){};
...
private:
...

};

class Festival{
public: 
    Festival(int budget): budget(budget), minPrice(0), maxNeededBudget(0), priceOffset(0), bandCounter(0){};
    ~Festival();
    StatusType AddBand(int bandID, int price, int votes=0);
    ...

private: 
    Tree<Band> bandTree;
    ...

};

StatusType Festival::AddBand(int bandID, int price, int votes){
    if ((price<0)||(bandID<0)){
        return INVALID_INPUT;
    }
    Band* newBand=NULL;
    try{
        newBand=new Band(bandID,price-priceOffset,votes);
    }
    catch(bad_alloc&){return ALLOCATION_ERROR;}
    if (bandTree.find(*newBand)!=NULL){
        delete newBand;
        return FAILURE;
    }
bandTree.add(*newBand);
....
}

في Tree.h:

template<class T>
class Tree{
public:
    Tree(T* initialData=NULL, Tree<T>* initialFather=NULL);
    void add(T& newData);
....
private:
....
};

ومن المثير للاهتمام ليس لدي أخطاء الربط عندما أحاول استخدام وظائف شجرة عند نوع T هو نوع بدائي مثل عدد صحيح.

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

المحلول

هل هناك Tree.cpp؟ إذا كان هناك، ربما كنت قد نسيت ربط ذلك؟ حيث يتم تنفيذ شجرة :: إضافة؟ وبالإضافة إلى ذلك أنا لا أرى فيها استدعاء شجرة :: إضافة. أعتقد أنه ينبغي أن يكون داخل بيان المحاولة، مباشرة بعد الجديد؟

ووللتذكير فقط:

لمعظم المجمعين (أي تلك التي تمارس تجميع منفصل) تنفيذ وظائف عضو فئة قالب يجب أن تكون واضحة خلال تجميع الملف المصدر الذي يستخدم فئة القالب. عادة الناس اتباع هذه القاعدة من خلال وضع تنفيذ وظائف الأعضاء داخل ملف الرأس.

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

والفرق بين الطبقات العادية والطبقات قالب موجود لأن الطبقات قالب ليست الطبقات "حقيقية" - هو، أيضا، قالب. إذا كنت قد حددت الدرجة شجرة ك الدرجة العادية، المترجم يمكن أن تستخدم الشفرة على الفور. في حالة وجود قالب المترجم أولا "يكتب" لك الطبقة الحقيقية، استبدال المعلمات القالب مع أنواع قمت بتوفيرها. الآن، مترجم يجمع ملفات حزب الشعب الكمبودي واحدا تلو الآخر. انه ليس على علم الملفات CPP الأخرى، ويمكن استخدام أي شيء من ملفات حزب الشعب الكمبودي الأخرى. دعنا نقول التطبيق الخاص بك من شجرة: إضافة يشبه هذا:

void Tree::add(T& newData)
{
    newData.destroyEverything();
}

ومن المشروع تماما طالما بك T ديه طريقة destroyEverything. عندما يجمع المترجم Class.cpp أنها تريد أن تتأكد من أنك لا تفعل أي شيء مع T أنها لا تعرف. وعلى سبيل المثال Tree<int> لا تعمل بسبب كثافة العمليات لم يقم destroyEverything. فإن المترجم محاولة لكتابة التعليمات البرمجية الخاصة بك مع كثافة العمليات بدلا من T ومعرفة أن الرمز لا ترجمة. ولكن منذ مترجم "يرى" فقط حزب الشعب الكمبودي الحالي وكل ما يشمل، وانها لن تكون قادرة على التحقق من صحة وظيفة إضافية، لأنها في حزب الشعب الكمبودي منفصل.

ولن يكون هناك أي مشكلة مع

void Tree::add(int& newData)
{
    newData.destroyEverything();
}

وتنفيذها في حزب الشعب الكمبودي منفصل لأن المترجم يعرف أن int هو نوع الوحيد المقبول، ويمكن أن "الاعتماد على نفسه" أنه عندما يحصل على تجميع Tree.cpp سيجد الخطأ.

نصائح أخرى

هل أنت متأكد من try / catch ديه أي شيء لتفعله حيال ذلك؟ ماذا يحدث إذا كنت ببساطة التعليق الخروج try وcatch خطوط، وترك بقية الكود كما هو عليه، وبناء ذلك؟

قد يكون مجرد أن كنت في عداد المفقودين المكتبة التي تعرف Tree::add(class Price &) من خط الرابط.

تحديث: باستخدام وظائف شجرة مع نوع بدائي لا يؤدي إلى خطأ ربط. لقد قمت بتحديث سؤالي في ضوء بعض الأمور التي قيل.

وكما ذكر البعض الآخر تحتاج إلى إظهار تنفيذ Treee :: إضافة ()، ويقول لنا كيف كنت ربطه.

في نقطة لا علاقة لها، إذا كنت تستخدم بنيات مثل:

  Band* newBand=NULL;
    try{
        newBand=new Band(bandID,price-priceOffset,votes);
    }
    catch(bad_alloc&){return ALLOCATION_ERROR;}

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

Band * newBand = new Band ( bandID, price - priceOffset, votes );

وبعد التمديد ربما:

Band newBand( bandID, price - priceOffset, votes );

وونسيان استثناء معالجة في هذه الحالة.

ولقد كتبت في تعليق:

<اقتباس فقرة>   

وفكرت في هذا ولكن وظيفة هو جزء من Tree.h، وأنا لا إدراجه. وظيفة محددة هي: قالب الفراغ شجرة :: إضافة (T & newData)؛ نحن نسميها على النحو التالي: priceTree.add (* newPriceNode)؛ في حين priceTree هو شجرة، وكلاهما تم تعريفها في ملف حزب الشعب الكمبودي في المسألة.

وبدلا من:

priceTree.add(*newPriceNode);

والمحاولة:

priceTree.add(newPriceNode); //no "*" before "newPriceNode"

وإضافة () يأخذ إشارة إلى عقدة، لا مؤشر إلى عقدة (وفقا لتعريفك للشجرة).

أنت تحصل أخطاء الربط، وليس مترجم أخطاء. هذا يخبرنا بأن المترجم يعرف أي نوع من وظيفة Tree::add() هو، ولكن لم يكن لديهم تعريف. في Tree.h، أرى إعلان وظيفة إضافية ()، ولكن ليس تعريفا. يبدو غريبا بالنسبة لي. لا أحد يعرف من أين جاء Tree.h من؟

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

وهكذا، أنا ذاهب الى الخروج على أطرافهم وتشير إلى أن التعاريف في ملف منفصل، لا ترتبط في، وأنه لا توجد أحكام في مكان آخر لinstantiating لأنواع أساسية مثل Tree<int>. هذا هو المفترض لتبسيط تجميع، كما يتم تجميع هذه الأمور عادة في أماكن متعددة، وهذا يستغرق وقتا.

ما عليك القيام به في هذه الحالة هو العثور حيث يتم إنشاء مثيل Tree<int>، وإضافة مثيل للفئة الخاصة بك.

ويمكن أن أكون بعيدا قاعدة هنا، ولكن شرحي لا تناسب الحقائق التي أعطيت.

تعديل بعد تصريحات الأولى : ل

وقوالب هي اصعب نوعا ما من وظائف عادية، والتي هي عادة ليست مشكلة حقيقية. وإذا كانت التعاريف لجميع المكالمات في Tree.h، ثم Festival.cpp ستكون قادرة على مثيل Tree<Band> وكل شيء سيكون باردا. هذا هو الأسلوب المعتاد، وكنت الوقوع في هذه المشكلة لأنك لا تستخدم ذلك.

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

لذلك، يجب أن يكون هناك بعض استخدام Tree<Band> في مكان ما في البرنامج، على أن يكون هناك وظيفة Tree<Band>::add() المترجمة. تعريف Tree<T>::add أن تكون متاحة للمترجم عندما يتم إنشاء مثيل Tree<Band>، لأن خلاف ذلك المترجم ليس لديه فكرة ما إلى ترجمة. في هذه الحالة، انها توليد استدعاء دالة، على ثقة بأنكم سوف نتأكد من يتم ترجمة وظيفة في مكان آخر.

لذلك، لديك لإنشاء مثيل Tree<Band> داخل ملف له الوصول إلى كل من تعريفات لTree<T> وBand. هذا يعني على الارجح ملف موجود، أو يشمل، Tree.cpp ويشمل Festival.h.

ورابط يستخدم بالفعل Tree.cpp، ولكن Tree.cpp لم يكن لديك Tree<Band> المحددة فيه، لذلك فإنه من معنى للرابط. نماذج مفيدة فقط للمترجم، ورابط يعمل فقط على ما ولدت المترجم من القوالب.

ووسيلة سريعة لحل هذه هي لاتخاذ تعريفات من Tree.cpp ووضعها في Tree.h. وسيكون ذلك من المرجح أن تزيد من تجميع وربط مرات، للأسف. تقنية أخرى هي مثيل يستخدم كل قالب في Tree.cpp، بحيث أنها سوف يتم تجميعها هناك.

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