تحذير مترجم GNU "الفئة لها وظائف افتراضية ولكنها مدمرة غير افتراضية"

StackOverflow https://stackoverflow.com/questions/127426

  •  02-07-2019
  •  | 
  •  

سؤال

لقد قمت بتعريف واجهة في C++، أي.فئة تحتوي فقط على وظائف افتراضية خالصة.

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

class ITest{
public:
    virtual void doSomething() = 0;

protected:
    ~ITest(){}
};

void someFunction(ITest * test){
    test->doSomething(); // ok
    // deleting object is not allowed
    // delete test; 
}

مترجم GNU يعطيني تحذيرًا قائلاً:

تحتوي الفئة "ITest" على وظائف افتراضية ولكنها مدمرة غير افتراضية

بمجرد حماية المدمر، ما الفرق بين جعله افتراضيًا أو غير افتراضي؟

هل تعتقد أنه يمكن تجاهل هذا التحذير أو إسكاته بأمان؟

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

المحلول

إنه خطأ إلى حد ما في المترجم.لاحظ أنه في الإصدارات الأحدث من المترجم لا يتم طرح هذا التحذير (على الأقل في الإصدار 4.3 لا يحدث ذلك).إن حماية المدمر وغير الافتراضي أمر مشروع تمامًا في حالتك.

يرى هنا للحصول على مقالة ممتازة كتبها هيرب سوتر حول هذا الموضوع.من المقال:

المبدأ التوجيهي رقم 4:يجب أن تكون أداة تدمير الفئة الأساسية إما عامة وافتراضية، أو محمية وغير افتراضية.

نصائح أخرى

تتعلق بعض التعليقات على هذه الإجابة بإجابة سابقة قدمتها، والتي كانت خاطئة.

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

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

إذا أصررت على القيام بذلك، فامضي قدمًا واجتاز -Wno-non-virtual-dtor إلى دول مجلس التعاون الخليجي.يبدو أن هذا التحذير لا يتم تشغيله افتراضيًا، لذا لا بد أنك قمت بتمكينه باستخدام -Wall أو -Weffc++.ومع ذلك، أعتقد أنه تحذير مفيد، لأنه في معظم الحالات قد يكون هذا خطأً.

إنها فئة واجهة، لذا فمن المعقول ألا تحذف الكائنات التي تنفذ تلك الواجهة عبر تلك الواجهة.إحدى الحالات الشائعة لذلك هي واجهة الكائنات التي أنشأها المصنع والتي يجب إعادتها إلى المصنع.(قد يكون وجود كائنات تحتوي على مؤشر إلى مصنعها مكلفًا للغاية).

وأنا أتفق مع الملاحظة القائلة بأن دول مجلس التعاون الخليجي تتذمر.بدلاً من ذلك، يجب أن يحذرك ببساطة عند حذف ITest*.وهنا يكمن الخطر الحقيقي.

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

أجد أنني أستخدم هذا النمط ('p' صغير) كثيرًا.في الواقع أجد أنه من الشائع أن تحتوي واجهاتي على dtors محمية أكثر من أن يكون لها واجهات عامة.ومع ذلك، لا أعتقد أنه في الواقع مصطلح شائع (لا يتم الحديث عنه كثيرًا) وأعتقد أنه عندما تمت إضافة التحذير إلى مجلس التعاون الخليجي، كان من المناسب محاولة فرض أن "dtor" الأقدم يجب أن يكون افتراضيًا إذا كنت لها قاعدة الوظائف الافتراضية.لقد قمت شخصيًا بتحديث هذه القاعدة إلى "يجب أن يكون dtor افتراضيًا إذا كان لديك وظائف افتراضية وترغب في أن يتمكن المستخدمون من حذف مثيلات الواجهة من خلال الواجهة وإلا يجب أن يكون dtor محميًا وغير افتراضي" منذ زمن طويل؛)

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

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

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