سؤال

أتخلى عن هذا ...

$ 5.2.7/2- "إذا كان t هو نوع مؤشر ، يجب أن يكون v rvalue من مؤشر لإكمال نوع الفئة ، والنتيجة هي rvalue من النوع T. نوع فئة كاملة ، والنتيجة هي lvalue من النوع المشار إليه من قبل T. "

وفقًا لما ورد أعلاه ، يجب أن يكون الرمز التالي جيدًا.

struct A{};
struct B : A{};

int main(){
   B b;
   A a, &ar1 = b;

   B& rb1 = dynamic_cast<B&>(ar1);  // Does not $5.2.7/2 apply here?
   B& rb2 = dynamic_cast<B&>(a);    // and also here?
}

لكنه ليس كذلك. جميع المترجمين يشكون من المعامل إلى عدم تعدد الأشكال الديناميكية

$ 5.2.7/6- خلاف ذلك ، يجب أن يكون V مؤشرًا أو lvalue من نوع متعدد الأشكال (10.3).

إذن سؤالي هو ماذا يعني $ 5.2.7/2؟ لماذا $ 5.2.7/6 ركلة هنا؟

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

المحلول

"خلاف ذلك" في هذه الحالة يعني ، "ما لم تنطبق الشروط في 5.2.7/5".

يمكنك معرفة ذلك لأن /2 يضع شرطًا على البرنامج بخصوص معامل dynamic_cast (لاحظ أن لغة "يجب" "V يجب أن تكون lvalue" مقابل "هي" لغة "النتيجة هي lvalue"). بشكل مشترك مع أماكن أخرى في المعيار ، فإن التعبير عن الشرط لا يعني بالضرورة أنه فقط المتطلبات. الجمل الأخرى يمكن أن تحدد متطلبات إضافية. في هذه الحالة ، ينص /6 على شرط إضافي لا ينطبق إلا في بعض الحالات ، اعتمادًا على T والنوع الثابت من V.

/3 ، /4 ، /5 يخبرك عن القيمة من النتيجة ، وهي متسقة تمامًا مع المتطلبات في /2. لا شيء منهم يبدأ بـ "خلاف ذلك". بالنسبة لي ، من الواضح إلى حد ما أنها لا تشكل سلسلة "أخرى إذا" تبدأ في /2.

قد تجعل بعض الأقواس أو شيء ما أكثر وضوحًا (أي أن "خلاف ذلك" في /6 ينطبق على "if" في /5 ، وليس إلى "if" في /2 أو /3 أو / /4). لكن هذا ليس أسلوب المنزل.

بصرف النظر عن أي شيء آخر ، فإن "خلاف ذلك" في /5 من الناحية المنطقية لا يمكن أن تنطبق بشكل مفيد على الظروف في /2. /1 يقول أن T يجب أن يكون "مؤشرًا أو مرجعًا إلى نوع الفصل الكامل ، أو السيرة الذاتية void* ". /2 يغطي حالتين - أنواع المؤشرات ، وأنواع المرجع. هذا هو كل شيء.

نصائح أخرى

حسنًا ، يجب ملاحظة جميع المتطلبات في 5.2.7 سويا او معا. لا يمكنك التوقف بعد 5.2.7/2 وبدء كتابة رمز من المفترض أن يرضي كل شيء "حتى 5.2.7/2". يحدد 5.2.7 بالكامل مواصفات dynamic_cast.

يتم تمييز الشرط متعدد الأشكال لأنه موجود الشرط. عندما تستخدم dynamic_cast بالنسبة للأعلى ، لا ينطبق متطلبات الأشكال (في الواقع ، dynamic_cast يعادل static_cast في Upcasts). لا ينطبق متطلبات الأشكال المتعددة إلا عند استخدامها dynamic_cast للهبوط أو المتقاطعات.

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

من أجل القيام مسبل كما هو الحال في مثالك ، يجب أن يكون بنية A متعددة الأشكال ، ولديه RTTI. إليك نسخة معدلة تعمل ، إلى حد ما:

struct A{virtual void f(){}};
struct B : A{};

int main(){
   B b;
   A a, &ar1 = b;

   B& rb1 = dynamic_cast<B&>(ar1);  // Does not $5.2.7/2 apply here?
   //B& rb2 = dynamic_cast<B&>(a);    // and also here?
}

عن طريق إضافة افتراضية تجعله متعدد الأشكال ، يتم تمكين RTTI للفئة ، مما يسمح بالانسحاب.

لاحظ أن مثالك الثاني لا يمكن أن ينجح - نظرًا لأنك تقوم بإلقاء جراب (a) إلى إشارة إلى جراب - وهو أمر غير مسموح به.


تحديث:

لا يُسمح بموجب الرمز الخاص بك بموجب 5.2.7.5 ولا يُسمح به بموجب 5.2.7.6. تعديلي يجعله يعمل أقل من 5.2.7.6

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