سؤال

أريد أن تقوم فئة أصل افتراضية خالصة باستدعاء تنفيذ فرعي لوظيفة مثل:

class parent
{
  public:
    void Read() { //read stuff }
    virtual void Process() = 0;
    parent() 
    {
        Read();
        Process();
    }
}
class child : public parent
{
  public:
    virtual void Process() { //process stuff }
    child() : parent() { }
}

int main()
{
   child c;
}

من المفترض أن ينجح هذا، لكني أتلقى خطأ غير مرتبط:/ هذا يستخدم VC++ 2k3

أو لا ينبغي أن تعمل، هل أنا مخطئ؟

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

المحلول

وعنوان المقالة التالي يقول كل شيء: أبدا دعوة وظائف افتراضية أثناء البناء أو تدمير .

نصائح أخرى

وبدلا من ذلك، جعل طريقة مصنع لخلق الأشياء وجعل منشئات القطاع الخاص، وطريقة مصنع يمكن أن ثم تهيئة الكائن بعد البناء.

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

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

هناك حلان:

  1. قم بإجراء استدعاء Process() في مُنشئ الفئة المشتقة
  2. قم بتعريف نص دالة فارغ للعملية كما في المثال التالي:
class parent
{
  public:
    void Read() { //read stuff }
    virtual void Process() { }
    parent() 
    {
        Read();
        Process();
    }
}

ومع خطوة واحدة أكثر هل يمكن أن مجرد تقديم نوع من وظيفة مثل

class parent
{
    public:
        void initialize() {
            read();
            process();
        }
}

وتحتاج إلى التفاف في داخل الكائن الذي يستدعي أسلوب ظاهري بعد يتم إنشاء الكائن الكامل:

class parent
{
  public:
    void Read() { /*read stuff*/ }
    virtual void Process() = 0;
    parent()
    {
        Read();
    }
};

class child: public parent
{
  public:
    virtual void Process() { /*process stuff*/ }
    child() : parent() { }
};

template<typename T>
class Processor
{
    public:
        Processor()
            :processorObj() // Pass on any args here
        {
            processorObj.Process();
        }
    private:
        T   processorObj;

};




int main()
{
   Processor<child> c;
}

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

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

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

من المحتمل أن يعمل هذا بشكل أفضل مع التجميع:قم بإعطاء وظيفة المعالجة لطريقة القالب ليتم استدعاؤها في الوقت المناسب.ربما يمكنك أن تفعل الشيء نفسه بالنسبة لوظيفة القراءة.

يمكن أن يتم التجميع بطريقتين:

  1. استخدام الوظائف الافتراضية (أي.ربط وقت التشغيل)
  2. استخدام القوالب (أي.ترجمة ملزمة الوقت)

مثال 1:ملزمة وقت التشغيل

class Data {};
class IReader    { public: virtual Data read()            = 0; };
class IProcessor { public: virtual void process( Data& d) = 0; };

class ReadNProcess {
public:
    ReadNProcess( IReader& reader, IProcessor processor ){
       processor.process( reader.read() );
    }
};

مثال 2:ربط وقت الترجمة

template< typename Reader, typename Writer > // definitely could use concepts here :)
class ReadNProcess {
public:
     ReadNProcess( Reader& r, Processor& p ) {
         p.process( r.read() );
     }
};
scroll top