2009-04-16 18 views
14

मुझे पता है कि यदि आप किसी सदस्य को नो-एर्ग कन्स्ट्रक्टर में प्रारंभिक सूची से बाहर छोड़ देते हैं, तो उस सदस्य के डिफ़ॉल्ट कन्स्ट्रक्टर को कॉल किया जाएगा।कन्स्ट्रक्टर प्रारंभिक सूचियों की प्रतिलिपि बनाएँ

क्या प्रतिलिपि बनाने वाले निर्माता सदस्यों की कॉपी कन्स्ट्रक्टर को कॉल करते हैं, या क्या वे डिफ़ॉल्ट कन्स्ट्रक्टर भी कहते हैं?

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()? 
} 
+2

देखें: http://stackoverflow.com/questions/563221/is-there-an-implicit-default-constructor-in-c/563320#563320 –

उत्तर

23

स्पष्ट रूप से परिभाषित प्रति रचनाकार सदस्यों के लिए कॉपी कन्स्ट्रक्टर को कॉल नहीं करते हैं।

जब आप एक निर्माता के शरीर में प्रवेश करते हैं, तो उस वर्ग के प्रत्येक सदस्य को प्रारंभ किया जाएगा। यही है, एक बार जब आप { पर पहुंच जाते हैं तो आपको गारंटी दी जाती है कि आपके सभी सदस्यों को प्रारंभ किया गया है।

निर्दिष्ट किए बिना, सदस्य डिफ़ॉल्ट रूप से कक्षा में दिखाई देने वाले क्रम में प्रारंभिक होते हैं। (और यदि वे नहीं हो सकते हैं, तो कार्यक्रम खराब हो गया है।) इसलिए यदि आप अपनी खुद की प्रतिलिपि निर्माता को परिभाषित करते हैं, तो अब आप किसी भी सदस्य प्रतिलिपि निर्माता को वांछित के रूप में कॉल करने के लिए तैयार हैं।

यहाँ के साथ चारों ओर एक छोटा सा कार्यक्रम आप कर सकते हैं कहीं कॉपी-पेस्ट और गंदगी है:

#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); 
} 

के रूप में-है, इस प्रिंट:

 
In Foo::Foo() 
In Bar::Bar() 
In Baz::Baz() 
Copying... 
In Foo::Foo() 
In Bar::Bar() 
In Baz::Baz(const Baz&) 

ध्यान दें कि यह के सदस्यों डिफ़ॉल्ट-आरंभ है Baz

स्पष्ट प्रतिलिपि निर्माता बाहर टिप्पणी करते हुए की तरह द्वारा:

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

उत्पादन इस बन जाएगा:

 
In Foo::Foo() 
In Bar::Bar() 
In Baz::Baz() 
Copying... 
In Foo::Foo(const Foo&) 
In Bar::Bar(const Bar&) 

यह दोनों पर कॉपी-निर्माता कहता है।

और यदि हम reintroduce Baz के निर्माता कॉपी और स्पष्ट रूप से एक भी सदस्य कॉपी:

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

हम पाते हैं:

 
In Foo::Foo() 
In Bar::Bar() 
In Baz::Baz() 
Copying... 
In Foo::Foo(const Foo&) 
In Bar::Bar() 
In Baz::Baz(const Baz&) 

आप देख एक बार आप स्पष्ट रूप से एक कॉपी-निर्माता घोषणा कर सकते हैं के रूप में आप सभी वर्ग के सदस्यों की प्रतिलिपि बनाने के लिए ज़िम्मेदार हैं; यह अब आपका कन्स्ट्रक्टर है।

यह चालक कन्स्ट्रक्टर समेत सभी रचनाकारों के लिए लागू होता है।

+0

यदि कोई सदस्य कच्चा सूचक (जैसे शून्य *) या int, double, आदि है - क्या उपयोगकर्ता द्वारा परिभाषित प्रति कन्स्ट्रक्टर 0 को असाइन करेगा उन्हें प्रवेश करने से पहले {यदि उपयोगकर्ता प्रतिलिपि बनाने वाले की प्रारंभिक सूची में इन सदस्यों को कुछ भी निर्दिष्ट नहीं करता है? –

+0

@SergeRogatch: यदि आप इसे स्पष्ट रूप से प्रारंभ नहीं करते हैं, तो मान नियमित रूप से अनियमित चर की तरह निर्दिष्ट नहीं है, और इसे पढ़ना अनिर्धारित व्यवहार है। आपको स्पष्ट रूप से पॉइंटर्स को शून्य, 0 से इत्यादि को प्रारंभ करना होगा, – GManNickG

2

हां। सीटीर्स सीटीओआर हैं।

+0

+1, आपने मुझे 2 सेकंड तक हराया। :) –

+1

-1: "हां" का अर्थ "या" वाले प्रश्न के उत्तर के रूप में क्या है? – mmmmmmmm

+1

rstevens, चार्ली ने जवाब देने के तुरंत बाद प्रश्न संपादित किया था। चार्ली ने मूल प्रश्न का पूरी तरह जवाब दिया। उस ने कहा, मैंने नीचे अपना जवाब संपादित किया है और मुझे लगता है कि यह काफी अच्छा है :) – GManNickG

2

किसी भी सदस्य परिवर्तक के लिए एक डिफ़ॉल्ट कन्स्ट्रक्टर है जो डिफ़ॉल्ट कन्स्ट्रक्टर को लागू किया जाता है यदि आपने स्पष्ट रूप से प्रारंभिक सूची में उस सदस्य चर के लिए कोई अन्य कन्स्ट्रक्टर कॉल नहीं जोड़ा है।

0

जब संकलक डिफ़ॉल्ट कर्क्टर प्रदान करता है, तो आपको लगता है कि कंपाइलर सदस्य चर के लिए क्या करता है? यह प्रतिलिपि बनाता है।

उसी नस में, यदि ग्राहक उपयोगकर्ता परिभाषित है, और यदि कोई सदस्य कुछ छोड़ देता है, तो उन सदस्यों को अनियमित नहीं छोड़ा जा सकता है। कक्षा के आविष्कारों को निर्माण के दौरान स्थापित किया जाता है और उन्हें लगातार बनाए रखा जाना चाहिए। तो, संकलक आपके लिए करता है।

+0

-1 क्षमा करें। एक कंपाइलर-प्रदान की गई डिफ़ॉल्ट प्रतिलिपि ctor * * उस सदस्य की अपनी प्रतिलिपि ctor (जो कि आदिम प्रकारों के मामले में एक बिटवाई प्रतिलिपि है) का उपयोग करके प्रत्येक सदस्य की प्रतिलिपि बनाएँ। –

+0

हाँ, लेकिन मैं वही बात कह रहा हूँ! * डिफ़ॉल्ट initilalizes * का मतलब सदस्य केक्टर के माध्यम से प्रतिलिपि बनाना है। – Abhay

+0

मैं देख रहा हूं कि आप क्या कह रहे हैं, लेकिन वास्तव में शब्द "डिफ़ॉल्ट प्रारंभिक" में C++ मानक में एक विशिष्ट, अच्छी तरह से परिभाषित अर्थ है, जो किसी ऑब्जेक्ट को प्रकार के डिफ़ॉल्ट मान के साथ प्रारंभ करना है (ठीक है, यह थोड़ा अधिक जटिल है लेकिन वैसे भी ...) तो आपका विवरण थोड़ा भ्रामक है। –

1

एक कॉपी कन्स्ट्रक्टर के बारे में जादुई कुछ भी नहीं है, इसके अलावा संकलक इसे आवश्यकतानुसार जोड़ देगा। लेकिन वास्तव में यह कैसे चलता है, इसमें कुछ भी खास नहीं है - यदि आप स्पष्ट रूप से "ऐसे और ऐसे कन्स्ट्रक्टर का उपयोग नहीं करते" कहते हैं, तो यह डिफ़ॉल्ट का उपयोग करेगा।

1

वीसी 9 में नहीं। दूसरों के बारे में निश्चित नहीं है।

// 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; 
} 
+0

और स्टडआउट था? –

2

जानकारी के लिए देखें: Is there an implicit default constructor in C++?

लघु:

  • संकलक जनरेट किया गया "डिफ़ॉल्ट निर्माता": प्रत्येक सदस्य के डिफ़ॉल्ट निर्माता का उपयोग करता है।
  • कंपाइलर जेनरेटेड "कॉपी कन्स्ट्रक्टर": प्रत्येक सदस्य की कॉपी कन्स्ट्रक्टर का उपयोग करता है।
  • कंपाइलर जेनरेटेड "असाइनमेंट ऑपरेटर": प्रत्येक सदस्य के असाइनमेंट ऑपरेटर का उपयोग करता है।
1

बेस कॉल कन्स्ट्रक्टर कैसे शुरू किया जाता है, इस पर निर्भर करता है कि सदस्य के रचनाकारों को वही तरीका कहा जाएगा। उदाहरण के लिए, के साथ शुरू करते हैं:

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 

का आनंद लें।

संबंधित मुद्दे