2009-05-11 14 views
19

के अंदर किसी ऑब्जेक्ट का निर्माण मैं सी ++ के लिए बिल्कुल नया हूं, और मुझे इस बारे में निश्चित नहीं है। निम्न उदाहरण देखें जो मेरी वर्तमान समस्या का सारांश देता है।सी ++ - कक्षा

class Foo 
{ 
    //stuff 
}; 

class Bar 
{ 
    Foo foo; 
}; 

तो बार में एक पूर्ण फू ऑब्जेक्ट है, न केवल संदर्भ या सूचक। क्या यह ऑब्जेक्ट इसके डिफ़ॉल्ट कन्स्ट्रक्टर द्वारा शुरू किया गया है? क्या मुझे अपने कन्स्ट्रक्टर को स्पष्ट रूप से कॉल करने की ज़रूरत है, और यदि हां, तो कैसे और कहाँ?

धन्यवाद।

+4

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

+2

काफी मजाकिया है कि @xtofl पोस्टर से 'मैं सी ++ से परिचित हूं' को हटाने का अनुरोध करता हूं ... शायद अधिकांश लोग सी ++ के साथ 'परिचित' नहीं होते हैं जब लगभग सभी उत्तर गलत होते हैं। वास्तव में प्रारंभिकरण कठिन है, कुछ लोगों ने उत्तर दिया है कि उनके सी ++ ज्ञान @ जेरेडपायर, @ डिर्ककली, @ डेविड थॉर्नली साबित हुए हैं और अभी भी असफल रहे हैं। –

उत्तर

17

यह द्वारा प्रारंभ की जाएगी इसके डिफ़ॉल्ट कन्स्ट्रक्टर।

class Foo 
{ 
    public: 
    Foo(int val) { } 
    //stuff 
}; 

class Bar 
{ 
    public: 
    Bar() : foo(2) { } 

    Foo foo; 
}; 
+0

सिंटेक्स त्रुटि: आपको सार्वजनिक कीवर्ड के बाद एक कोलन (:) चाहिए। – dirkgently

+2

और प्रत्येक वर्ग के समापन के बाद अर्ध कोलन (;)। मैं जावा को दोष देता हूं। – richq

+0

वाक्यविन्यास सुधार के लिए धन्यवाद। मैं सी # दोष। –

1

So Bar constains a full Foo object, not just a reference or pointer. Is this object initialized by its default constructor?

तो Foo एक डिफ़ॉल्ट ctor, प्रकार Foo का एक उद्देश्य है जब आप प्रकार Bar की एक वस्तु बनाने डिफ़ॉल्ट ctor का उपयोग करेंगे है। अन्यथा, आपको Foo ctor स्वयं को कॉल करने की आवश्यकता है या आपके Bar का ctor आपके कंपाइलर को loduly शिकायत करेगा।

उदाहरण के लिए: ऊपर के उदाहरण को संशोधित रूप में निम्नानुसार

"In constructor 'Bar::Bar()': Line 5: error: no matching function for call to 'Foo::Foo()'

Do I need to explicitly call its constructor, and if so, how and where ?

:

class Foo { 
public: 
Foo(double x) {} 
}; 

class Bar { 
Foo x; 
}; 

int main() { 
Bar b; 
} 

ऊपर संकलक होगा की तरह कुछ शिकायत

class Foo { 
public: 
    Foo(double x) {} // non-trivial ctor 
}; 

class Bar {  
Foo x; 
public: 
    Bar() : x(42.0) {} // non-default ctor, so public access specifier required 
}; 

int main() { 
Bar b; 
} 
+0

यदि फू के पास कोई कन्स्ट्रक्टर परिभाषित नहीं है (संभावित रूप से कॉपी कन्स्ट्रक्टर के अलावा) तो कंपाइलर बिल्कुल शिकायत नहीं करेगा लेकिन यह स्पष्ट रूप से परिभाषित फू कन्स्ट्रक्टर को कॉल नहीं करेगा। वस्तु अनियमित हो जाएगी। –

+0

यही वह है जिसका मतलब मैं डिफ़ॉल्ट ctor से था। – dirkgently

+0

प्रारंभिक सूचियों का उपयोग किए बिना ऑब्जेक्ट को प्रारंभ करना संभव है? जैसा कि, क्या आप ऑब्जेक्ट को कन्स्ट्रक्टर के {} के अंदर प्रारंभ कर सकते हैं? –

2

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

Bar::Bar() : foo(42) {} 

यह आपको कोड :)

+1

मुझे लगता है कि आप में से अधिकांश आपके उदाहरणों में "42" के साथ आए थे। वह कहां से आता है? – ichiban

+7

यह एच 2 जी 2 का संदर्भ है - जीवन, ब्रह्मांड, और सब कुछ के अंतिम प्रश्न का उत्तर। पढ़ें: http://en.wikipedia.org/wiki/42_(number)#In_The_Hitchhiker.27s_Guide_to_the_Galaxy। डगलस एडम्स को भी बेहतर पढ़ें। – dirkgently

+0

@ichiban, @dirkgently सही है। – JaredPar

1

पूर्ण ऑब्जेक्ट में एक फू :: फू (int) जोड़ने संभालने निश्चित रूप से है द्वारा इस पर नियंत्रण कर सकते हैं। नहीं, यह डिफ़ॉल्ट रूप से बार के डिफ़ॉल्ट कन्स्ट्रक्टर में बनाया गया है।

अब, अगर फू के पास एक कन्स्ट्रक्टर था जो केवल एक int कहता था।

class Foo { 
public: 
    Foo(int x) { .... } 
}; 

class Bar { 
public: 
    Bar() : foo(42) {} 

    Foo foo; 
}; 

लेकिन अगर फू एक डिफ़ॉल्ट निर्माता फू() था, संकलक स्वचालित रूप से बार के निर्माता उत्पन्न करता है, और कहा कि फू के डिफ़ॉल्ट कहेंगे: आप फू के निर्माता कहते हैं, और कहते हैं कि क्या है करने के लिए बार में एक निर्माता आवश्यकता होगी (यानी फू())

+0

मुझे लगता है कि आप में से अधिकांश आपके उदाहरणों में "42" के साथ आए थे। वह कहां से आता है? – ichiban

+0

काम नहीं करेगा, सभी ctors डिफ़ॉल्ट रूप से निजी हैं। – dirkgently

+0

ओह। फिक्स्ड। जब मैं अन्य अवधारणाओं के बारे में सोच/बात करता हूं तो मैं इसे छोड़ देता हूं। – Macke

1

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

Bar::Bar(int baz) : foo(baz) 
{ 
    // Rest of the code for Bar::Bar(int) goes here... 
} 
+0

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

+0

प्रारंभिक सूचियों का उपयोग किए बिना ऑब्जेक्ट को प्रारंभ करना संभव है? जैसा कि, क्या आप ऑब्जेक्ट को कन्स्ट्रक्टर के {} के अंदर प्रारंभ कर सकते हैं? –

+0

@ जस्टिन लिआंग, नहीं, एक बार जब कन्स्ट्रक्टर के शरीर को किसी भी ऑब्जेक्ट को निष्पादित किया जाता है जो कि कक्षा का हिस्सा होता है जिसे प्रारंभ किया जाएगा। यदि ऑब्जेक्ट में डिफॉल्ट कन्स्ट्रक्टर नहीं है, तो प्रारंभकर्ता सूची में कन्स्ट्रक्टर को कॉल करना आवश्यक है। हालांकि, आप वर्ग में ऑब्जेक्ट्स और डेटा को बदलने के लिए असाइनमेंट का उपयोग कर सकते हैं, लेकिन चेतावनी दी जानी चाहिए कि ऑब्जेक्ट प्रारंभ होने के बाद यह कम कुशल है और फिर असाइनमेंट के साथ ओवरराइट किया गया है। – Naaff

0

आप सी ++ में स्पष्ट रूप से डिफ़ॉल्ट contructor कॉल करने के लिए की जरूरत नहीं है, यह आप के लिए बुलाया जाएगा। आप एक अलग contructor फोन करना चाहता था, तो आप ऐसा कर सकते हैं:

Foo foo(somearg) 
+0

यदि फू के पास उपयोगकर्ता ने डिफॉल्ट कन्स्ट्रक्टर को परिभाषित किया है तो इसे कॉल किया जाएगा। फू में एक निश्चित रूप से परिभाषित डिफ़ॉल्ट कन्स्ट्रक्टर के लिए, बार –

4

चार कार्य कर रहे हैं, तो यह कर सकते हैं सी ++ संकलक, प्रत्येक वर्ग के लिए उत्पन्न होगा, और आप उन्हें प्रदान नहीं करते हैं: एक डिफ़ॉल्ट निर्माता , एक प्रतिलिपि निर्माता, एक असाइनमेंट ऑपरेटर, और एक विनाशक।सी ++ मानक (अध्याय 12, "विशेष कार्य") में, इन्हें "निहित रूप से घोषित" और "निहित रूप से परिभाषित" के रूप में जाना जाता है। उनके पास सार्वजनिक पहुंच होगी।

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

तो, क्या हो रहा है कि कक्षा फू का निहित रूप से परिभाषित डिफ़ॉल्ट कन्स्ट्रक्टर है, और बार (जो उपयोगकर्ता द्वारा परिभाषित कन्स्ट्रक्टर नहीं लगता है) इसके निहित परिभाषित डिफ़ॉल्ट कन्स्ट्रक्टर का उपयोग करता है जो फू के डिफ़ॉल्ट कन्स्ट्रक्टर को कॉल करता है।

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

याद रखें कि, यदि आप फू के लिए एक कन्स्ट्रक्टर लिखते हैं, तो संकलक स्वचालित रूप से एक डिफ़ॉल्ट कन्स्ट्रक्टर उत्पन्न नहीं करेगा, और इसलिए आपको एक को निर्दिष्ट करने के लिए एक निर्दिष्ट करना होगा। इसलिए, यदि आपको Foo की परिभाषा में Foo(int n); जैसे कुछ डालना था, और स्पष्ट रूप से एक डिफ़ॉल्ट कन्स्ट्रक्टर (या तो Foo(); या Foo(int n = 0);) नहीं लिखा था, तो आपके पास वर्तमान बार में बार नहीं हो सका, क्योंकि यह उपयोग नहीं कर सका फू का डिफॉल्ट कन्स्ट्रक्टर। इस मामले में, आपको Bar(int n = 0): foo(n) {} जैसे कन्स्ट्रक्टर रखना होगा जिसमें बार कन्स्ट्रक्टर फू को प्रारंभ करेगा। (ध्यान दें कि Bar(int n = 0) {foo = n;} या ऐसा काम नहीं करेगा, क्योंकि बार कन्स्ट्रक्टर पहले foo को प्रारंभ करने का प्रयास करेगा, और यह असफल हो जाएगा।)

+0

के निहित रूप से परिभाषित कन्स्ट्रक्टर में कोई कॉल नहीं किया जाएगा बार में अंतर्निहित परिभाषित कन्स्ट्रक्टर फू में एक स्पष्ट रूप से परिभाषित कन्स्ट्रक्टर को कॉल नहीं करेगा। यदि फू के पास एक उपयोगकर्ता परिभाषित कन्स्ट्रक्टर है तो बार अंतर्निहित रूप से परिभाषित कन्स्ट्रक्टर (इस बार हाँ) उपयोगकर्ता को फू में परिभाषित कन्स्ट्रक्टर को कॉल करेगा। यह यहां तक ​​का सबसे पूरा उत्तर है: +1 –

+0

इसके बारे में निश्चित है? 12.6.2 (4) के अनुसार, प्रारंभिक सूची में उल्लिखित नहीं होने पर, एक गैर-स्टेटिक डेटा सदस्य को इसके डिफ़ॉल्ट कन्स्ट्रक्टर के साथ प्रारंभ किया जाता है, और 8.5 (5) में डिफ़ॉल्ट कन्स्ट्रक्टर को तब तक कॉल किया जाता है जब तक कि यह एक पीओडी नहीं है (सादा पुराना डेटा, जिसे आसानी से परिभाषित नहीं किया जाता है मानक में) प्रकार, जिस स्थिति में यह शून्य के लिए शुरू किया गया है। तो, मुझे लगता है कि सवाल यह है कि क्या फू एक पीओडी प्रकार है, जिसे हम नहीं देखते हैं। यदि यह पीओडी प्रकार है, तो यह सब शून्य-प्रारंभिक है; यदि इसमें ऐसी चीजों में से एक है जो इसे गैर-पीओडी के रूप में चिह्नित करती है, तो यह डिफ़ॉल्ट-प्रारंभिक है और इसलिए निहित परिभाषित डिफ़ॉल्ट कन्स्ट्रक्टर को कॉल करता है। –

12

निर्माण C++ में एक काफी कठिन विषय है। सरल उत्तर है यह पर निर्भर करता है। चाहे फू प्रारंभ किया गया हो या नहीं, फू की परिभाषा पर निर्भर करता है। दूसरे प्रश्न के बारे में: बार को प्रारंभ करने के लिए कैसे करें: आरंभिक सूचियां उत्तर हैं।

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

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

class Foo { 
    int x; 
public: 
    void dump() { std::cout << x << std::endl; } 
    void set() { x = 5; } 
}; 
class Bar { 
    Foo x; 
public: 
    void dump() { x.dump(); } 
    void set() { x.set(); } 
}; 
class Bar2 
{ 
    Foo x; 
public: 
    Bar2() : Foo() {} 
    void dump() { x.dump(); } 
    void set() { x.set(); } 
}; 
template <typename T> 
void test_internal() { 
    T x; 
    x.dump(); 
    x.set(); 
    x.dump(); 
} 
template <typename T> 
void test() { 
    test_internal<T>(); 
    test_internal<T>(); 
} 
int main() 
{ 
    test<Foo>(); // prints ??, 5, 5, 5, where ?? is a random number, possibly 0 
    test<Bar>(); // prints ??, 5, 5, 5 
    test<Bar2>(); // prints 0, 5, 0, 5 
} 

अब, अगर फू तो एक उपयोगकर्ता परिभाषित निर्माता था यह होगा इस बात पर ध्यान दिए बिना कि बार उपयोगकर्ता ने कन्स्ट्रक्टर को प्रारंभ किया है या नहीं। यदि बार में उपयोगकर्ता परिभाषित कन्स्ट्रक्टर है जो फू के स्पष्ट रूप से (संभावित रूप से परिभाषित) कन्स्ट्रक्टर को स्पष्ट रूप से कॉल करता है, तो वास्तव में फू को प्रारंभ किया जाएगा। यदि बार की प्रारंभिक सूची फू कन्स्ट्रक्टर को कॉल नहीं करती है तो यह उस मामले के बराबर होगी जहां बार में कोई उपयोगकर्ता परिभाषित कन्स्ट्रक्टर नहीं था।

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

प्रत्येक परीक्षण रन में, मुद्रित पहला मान प्रारंभिक मान (यदि यह वास्तव में प्रारंभ किया गया था) या उस स्मृति स्थिति में मान है, तो कुछ मामलों में 0 होना होता है। दूसरा मान केवल एक परीक्षण है टोकन मैन्युअल रूप से इसे बदलने के बाद स्मृति स्थिति पर मान का प्रतिनिधित्व करता है। तीसरा मान फ़ंक्शन के दूसरे भाग से आता है। यदि चर प्रारंभ किया जा रहा है तो यह 0 पर वापस आ जाएगा। यदि ऑब्जेक्ट प्रारंभ नहीं किया गया है, तो इसकी मेमोरी पुरानी सामग्री रखेगी।

+0

क्या आप जानते हैं कि जब आप () परीक्षण करते हैं तो आउटपुट ??, 5, 5, 5 के बजाय ??, 5, 5, 5 क्यों है? 5, फू ऑब्जेक्ट (x) स्कोप से बाहर नहीं जाता है जब test_internal रिटर्न ? इसी प्रकार परीक्षण () के लिए? – user1084113

+0

@ user1084113: क्योंकि यह अपरिभाषित व्यवहार है, इसलिए आप या तो प्राप्त कर सकते हैं, लेकिन परीक्षण इस बात का दुरुपयोग करता है कि कंपाइलर्स/आर्किटेक्चर आमतौर पर ढेर का उपयोग कैसे करते हैं। असल में, जब कोई फ़ंक्शन दर्ज किया जाता है तो यह अपने आंतरिक चर के लिए स्टैक के एक टुकड़े को पकड़ता है जो तब समाप्त होता है जब फ़ंक्शन समाप्त होता है (कॉलिंग कन्वेंशन के आधार पर यह कॉलर या फ़ंक्शन पॉइंटर को अपडेट करने वाला फ़ंक्शन हो सकता है)। फ़ंक्शन के लिए दूसरी कॉल उसी क्रम में रखी गई स्थानीय चर के लिए स्मृति के समान ब्लॉक का उपयोग करती है। 'X' अनियमित है, जिसमें फ़ंक्शन के अंतिम भाग में असाइन किया गया मान है। –

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