ألا توجد وسيلة لإعدادها إلى فئة مجردة وعدم تعديلها في كل مرة يتم فيها اشتقاق فئة منه؟

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

سؤال

#include<iostream>
using namespace std;

class Abs
{
        public:
        virtual void hi()=0;
};

class B:public Abs
{
        public:
        void hi() {cout<<"B Hi"<<endl;}
        void bye() {cout<<"B Bye"<<endl;}
};
class C:public Abs
{
        public:
        void hi() {cout<<"C Hi"<<endl;}
        void sayonara() {cout<<"C Sayonara"<<endl;}
};

int main()
{
        Abs *bb=new B;
        bb->bye();
        Abs *cc=new C;
        cc->sayonara();
}//main

يقول المترجم

test2.cpp: In function ‘int main()’:
test2.cpp:26: error: ‘class Abs’ has no member named ‘bye’
test2.cpp:28: error: ‘class Abs’ has no member named ‘sayonara’

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

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

المحلول

حسنًا ، لست متأكدًا من فهم ما تريده بالضبط (ولماذا تريده بهذه الطريقة) ولكن:

int main()
{
        Abs *bb=new B;
        static_cast<B*>(bb)->bye();
        Abs *cc=new C;
        static_cast<C*>(cc)->sayonara();
}//main

سيعمل.

عليك فقط أن تتأكد من ذلك bb هو حقا B* قبلك static_cast.

يمكنك أيضا استخدام dynamic_cast الذي سيعود مؤشر فارغ إذا bb ليس من النوع الصحيح.

نصائح أخرى

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

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

int main()
{
        B *bb = new B;
        bb->bye();
        C *cc=new C;
        cc->sayonara();
}//main

بهذه الطريقة لم تعد هناك حاجة إلى التعديلات في الفصل الأساسي :)

الصب الديناميكي هو خيار معقول. إذا كنت متدينًا بشأن القوالب الديناميكية ، فيمكنك استخدام نمط تصميم الزوار:

struct Abs;
struct B;
struct C;

struct Visitor
{
    virtual ~Visitor() {}

    // Provide sensible default actions
    virtual void visit(Abs&) const { throw "not implemented"; }
    virtual void visit(B& b) const { visit(static_cast<Abs&>(b)); }
    virtual void visit(C& c) const { visit(static_cast<Abs&>(c)); }
};

struct Abs
{
    virtual ~Abs() {}
    virtual void hi() = 0;
    virtual void accept(Visitor const& v) { v.visit(*this); }
};

struct B : Abs
{
    void hi() { ... }
    void accept(Visitor const& v) { v.visit(*this); }
    void bye() { ... }
};

struct C : Abs
{
    void hi() { ... }
    void accept(Visitor const& v) { v.visit(*this); }
    void sayonara() { ... }
};

struct DoSayonara : Visitor
{
    void visit(C& c) const { c.sayonara(); }
};

struct DoBye : Visitor
{
    void visit(B& b) const { b.bye(); }
};

struct ByeOrSayonara : Visitor
{
    void visit(B& b) const { b.bye(); }
    void visit(C& c) const { c.sayonara(); }
};

ثم تستخدم

Abs* b = new B(); Abs* c = new C();
b->accept(DoSayonara()); // Throw an exception
c->accept(DoSayonara()); // Do what is expected

افعل هذا فقط عندما تحتاجه حقًا.

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

ومع ذلك ، في مرحلة معينة من الوقت ، إما أن تعرف أن الكائن هو فئة فرعية محددة ، وفي هذه الحالة يمكنك إلقاء هذا النوع ديناميكيًا ، أو لا يمكنك التأكد من أنه يمكنك الاتصال بالوظيفة.

على افتراض أن هذا مرتبط بك سؤال آخر, ، حاولت شرح طريقة لتنفيذ هذه المشكلة بالذات بطريقة مختلفة هناك.

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