سؤال

أعلم أنه إذا تركت عضوا خارج قائمة التهيئة في منشئ NO-ARG، فسيتم استدعاء المنشئ الافتراضي لهذا العضو.

هل نسخ المنشئين بالمثل استدعاء منشئ نسخ للأعضاء، أو هل يتصلون أيضا بالبناء الافتراضي؟

class myClass {
  private:
    someClass a;
    someOtherClass b;
  public:
    myClass() : a(DEFAULT_A) {} //implied is b()
    myClass(const myClass& mc) : a(mc.a) {} //implied is b(mc.b)??? or is it b()?
}
هل كانت مفيدة؟

المحلول

لا يتصل منشئ النسخ المحدد بوضوح بنسخ منشئين للأعضاء.

عند إدخال جسم المنشئ، سيتم تهيئة كل عضو في تلك الفئة. وهذا هو، بمجرد أن تصل إلى { أنت مضمون بأن يتم تهيئة جميع أعضائك.

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

فيما يلي برنامج صغير يمكنك نسخ عجينة في مكان ما ويبلوي مع:

#include <iostream>

class Foo {
public:
    Foo() {
        std::cout << "In Foo::Foo()" << std::endl;
    }

    Foo(const Foo& rhs) {
        std::cout << "In Foo::Foo(const Foo&)" << std::endl;
    }
};

class Bar {
public:
    Bar() {
        std::cout << "In Bar::Bar()" << std::endl;
    }

    Bar(const Bar& rhs) {
        std::cout << "In Bar::Bar(const Bar&)" << std::endl;
    }
};

class Baz {
public:
    Foo foo;
    Bar bar;

    Baz() {
        std::cout << "In Baz::Baz()" << std::endl;
    }

    Baz(const Baz& rhs) {
        std::cout << "In Baz::Baz(const Baz&)" << std::endl;
    }
};

int main() {
    Baz baz1;
    std::cout << "Copying..." << std::endl;
    Baz baz2(baz1);
}

كما هو، هذه المطبوعات:

في Foo :: Foo () في Bar :: Bar () في Baz :: Baz () نسخ ... في فو :: Foo () في Bar :: Bar () في باز :: Baz (Const Baz &)

لاحظ أنه هو التهيئة الافتراضية أعضاء Baz.

من خلال التعليق على منشئ نسخة واضحة، مثل:

/*
Baz(const Baz& rhs) {
    std::cout << "In Baz::Baz(const Baz&)" << std::endl;
}
*/

سيصبح الناتج هذا:

في Foo :: Foo () في Bar :: Bar () في Baz :: Baz () نسخ ... في Foo :: Foo (Const Foo &) في Bar :: Bar (Const Bar &)

يستدعي المنشئ النسخة على حد سواء.

وإذا عدنا إعادة Bazنسخ المنشئ ونسخ عضو واحد بشكل صريح:

Baz(const Baz& rhs) :
    foo(rhs.foo)
{
    std::cout << "In Baz::Baz(const Baz&)" << std::endl;
}

نحن نحصل:

في Foo :: Foo () في Bar :: Bar () في Baz :: Baz () نسخ ... في فو :: Foo (Const Foo &) في Bar :: Bar () في باز :: باز (Const Baz &)

كما ترون، بمجرد أن تعلن صراحة منشئ نسخة أنت هي المسؤولة عن نسخ جميع أعضاء الفصل؛ إنه منشئك الآن.

ينطبق هذا على جميع المنشئين، بما في ذلك التحولات المصانعين.

نصائح أخرى

نعم. CTORS هي CTORS.

بالنسبة لأي متغير عضو لديه منشئ افتراضي يتم استدعاء المنشئ الافتراضي إذا لم تقم بإضافة أي استدعاء منشئ آخر بصراحة لمتغير هذا العضو في قائمة التهيئة.

لمزيد من التفاصيل: هل يوجد منشئ افتراضي ضمني في C ++؟

قصيرة:

  • مترجم تم إنشاؤه "المنشئ الافتراضي": يستخدم المنشئ الافتراضي لكل عضو.
  • تم إنشاء برنامج التحويل البرمجي "نسخ منشئ": يستخدم منشئ نسخ كل عضو.
  • برنامج التحويل البرمجي الذي تم إنشاؤه "عامل التعيين": يستخدم مشغل التعيين لكل عضو.

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

ليس في VC9. غير متأكد من الآخرين.

// compiled as: cl /EHsc contest.cpp
//
//    Output was:
//    Child1()
//    -----
//    Child1()
//    Child2()
//    Parent()
//    -----
//    Child1(Child1&)
//    Child2()
//    Parent(Parent&)

#include <cstdio>

class Child1 {
    int x;
public:
    static Child1 DEFAULT;

    Child1(){
        x = 0;
        printf("Child1()\n");
    }

    Child1(Child1 &other){
        x = other.x;
        printf("Child1(Child1&)\n");
    }
};

Child1 Child1::DEFAULT;

class Child2 {
    int x;
public:
    Child2(){
        x = 0;
        printf("Child2()\n");
    }

    Child2(Child2 &other){
        x = other.x;
        printf("Child2(Child2&)\n");
    }
};

class Parent {
    int x;
    Child1 c1;
    Child2 c2;

public:
    Parent(){
        printf("Parent()\n");
    }

    Parent(Parent &other) : c1(Child1::DEFAULT) {
        printf("Parent(Parent&)\n");
    }
};

int main(){
    printf("-----\n");
    Parent p1;
    printf("-----\n");
    Parent p2(p1);

    return 0;
}

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

struct ABC{
    int a;
    ABC() : a(0)    {   printf("Default Constructor Called %d\n", a);   };

    ABC(ABC  & other )  
    {
        a=other.a;
        printf("Copy constructor Called %d \n" , a ) ;
    };
};

struct ABCDaddy{
    ABC abcchild;
};

يمكنك القيام بهذه الاختبارات:

printf("\n\nTest two, where ABC is a member of another structure\n" );
ABCDaddy aD;
aD.abcchild.a=2;

printf( "\n Test: ABCDaddy bD=aD;  \n" );
ABCDaddy bD=aD; // Does call the copy constructor of the members of the structure ABCDaddy ( ie. the copy constructor of ABC is  called)

printf( "\n Test: ABCDaddy cD(aD); \n" );
ABCDaddy cD(aD);    // Does call the copy constructor of the members of the structure ABCDaddy ( ie. the copy constructor of ABC is  called)

printf( "\n Test: ABCDaddy eD; eD=aD;  \n" );
ABCDaddy eD;
eD=aD;          // Does NOT call the copy constructor of the members of the structure ABCDaddy ( ie. the copy constructor of ABC is not called)

انتاج:

Default Constructor Called 0

Test: ABCDaddy bD=aD;
Copy constructor Called 2

Test: ABCDaddy cD(aD);
Copy constructor Called 2

Test: ABCDaddy eD; eD=aD;
Default Constructor Called 0

استمتع.

عندما يوفر برنامج التحويل البرمجي الاستقرار الافتراضي، ما الذي تعتقد أن التحويل البرمجي يقوم به لمتغيرات الأعضاء؟ هو - هي نسخ بناء هو - هي.

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

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