سؤال

لدي مثال مفتعل التالي (قادم من رمز حقيقي):

template <class T>
class Base {
public:
 Base(int a):x(a) {}
    Base(Base<T> * &other) { }
    virtual ~Base() {}
private:
 int x;
};

template <class T>
class Derived:public Base<T>{
public:
  Derived(int x):Base<T>(x) {}
  Derived(Derived<T>* &other): Base<T>(other) {}

};


int main() {
 Derived<int> *x=new Derived<int>(1);
 Derived<int> y(x);
}

عندما أحاول تجميع هذا ، أحصل على:

1X.cc: In constructor ‘Derived<T>::Derived(Derived<T>*&) [with T = int]’:
1X.cc:27:   instantiated from here
1X.cc:20: error: invalid conversion from ‘Derived<int>*’ to ‘int’
1X.cc:20: error:   initializing argument 1 of ‘Base<T>::Base(int) [with T = int]’

1) من الواضح أن مجلس التعاون الخليجي يتم الخلط بينه من قبل البنائين. إذا قمت بإزالة المرجع من البنائين ، فإن الرمز يجمع. لذا فإن افتراضي هو أن هناك خطأ ما في مراجع مؤشر الصب. هل يمكن لأحد أن يخبرني ما الذي يحدث هنا؟

2) سؤال غير ذي صلة قليلاً. إذا كنت سأفعل شيئًا مروعًا مثل "حذف الآخر" في المُنشئ (تحمل معي) ، ماذا يحدث عندما يمررني شخص ما مؤشرًا على شيء ما على المكدس؟

E.g. Derived<int> x(2);
     Derived<int> y(x);

where 

 Derived(Derived<T>*& other) { delete other;}

كيف يمكنني التأكد من أن المؤشر يشير بشكل شرعي إلى شيء ما على الكومة؟

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

المحلول

Base<T> هو نوع قاعدة من Derived<T>, ، لكن Base<T>* ليس نوعًا أساسيًا من Derived<T>*. يمكنك تمرير مؤشر مشتق بدلاً من مؤشر أساسي ، لكن لا يمكنك تمرير مرجع مؤشر مشتق بدلاً من مرجع مؤشر أساسي.

والسبب هو أنه ، لنفترض أنك تستطيع ، ونفترض أن مُنشئ القاعدة هو كتابة بعض القيمة في المرجع:

Base(Base<T> * &other) {
    Base<T> *thing = new Base<T>(12);
    other = thing;
}

لقد كتبت للتو مؤشرًا إلى شيء ما ليس أ Derived<T>, في مؤشر ل Derived<T>. لا يمكن للمترجم أن يترك هذا يحدث.

نصائح أخرى

  1. لا يمكنك تحويل مرجع إلى مؤشر إلى مشتق إلى إشارة إلى مؤشر إلى قاعدة. (لا تسهم القوالب في المشكلة هنا ، لذا تمت إزالتها من مثالي أدناه.)
  2. إذا كنت ترغب في تأجيل المسؤولية عن مؤشر ، فاستخدم نوع المؤشر الذكي. يمكن أن تمثل أنواع المؤشرات الذكية "مسؤولية حذف" التي لا يمكن أن تكون المؤشرات الأولية. ومن الأمثلة على ذلك std :: auto_ptr و Boost :: shared_ptr, ، من بين عدة آخرين.

لماذا لا يمكنك مراجع مؤشر المؤشر:

struct Base {};
struct Derived : Base {};
struct Subclass : Base {};

int main() {
  Derived d;
  Derived* p = &d;
  Derived*& d_ptr = p;

  Base*& b_ptr = d_ptr; // this is not allowed, but let's say it is

  Base b;
  b_ptr = &b; // oops! d_ptr no longer points to a Derived!

  Subclass s;
  b_ptr = &s; // oops! d_ptr no longer points to a Derived!
}

عندما تمرر معلمة "أخرى" إلى CTOR القاعدة ، فأنت تحاول أن تفعل الشيء نفسه مثل b_ptr = d_ptr في الاعلى.

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

هذه هي الطريقة التي تعمل بها المكتبة القياسية - غالبًا ما تصطدم بالأخطاء الواضحة ، ولكن ليس من المطلوب ، الأمر متروكًا للمتصلة للتأكد من عدم القيام بأي شيء غبي.

لك x المتغير ليس مؤشرًا ، يجب أن يكون إذا كنت تريد تعيين أ new Derived<int> لذلك.

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

لست متأكدًا لماذا تريد الإشارة إلى المؤشر. لما لا

Base(Base<T> * other) { }

و

Derived(Derived<T>* other): Base<T>(other) {}

التي يجب أن تعمل.

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

يحرر: لماذا لا يمكن للمرء أن يفعل ما تحاول: النظر في مثال:

Derived1<int> *x = new Derived1<int>
Base<int> **xx =&x;
Derived2<int> y;
*xx = &y;

حيث اشتقت 1 و derived2 مختلف الفصول المستمدة من القاعدة؟ هل تعتقد أنه شرعي؟ الآن بعد أن قام X من النوع Derived1* بالتقاطات إلى Derived2؟

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