2011-11-08 9 views
24

सवाल बहुत सीधे आगे है। स्पष्टता के लिए, नीचे दिए गए उदाहरण पर विचार करें:कक्षा के तरीके कक्षा के उदाहरणों के आकार में वृद्धि करते हैं?

// Note that none of the class have any data members 
// Or if they do have data members, they're of equal size, type, and quantity 
class Foo { 
public: 
    void foo1(); 
    void foo2(); 
    // 96 other methods ... 
    void foo99(); 
}; 

class Bar { 
public: 
    // Only one method 
    void bar(); 
}; 

class Derived1 : public Foo { }; 
class Derived2 : public Bar { }; 

int main() { 
    Foo f; 
    Bar b; 
    Derived1 d1; 
    Derived2 d2; 
    return 0; 
} 

उदाहरणों f, b, d1, और d2 सभी स्मृति में अंतरिक्ष की एक ही राशि पर कब्जा? इस प्रश्न के विस्तार के रूप में, Foo के उदाहरणों को प्रतिलिपि करते समय Bar से अधिक समय लेते समय सैद्धांतिक रूप से?

+0

99 तरीके? arrgh .. – Nim

+0

@Nim: मैं वास्तव में बिंदु को प्राप्त करना चाहता था।;) गैर-आभासी तरीकों के लिए – Zeenobit

उत्तर

21

केवल उदाहरण डेटा (सभी कार्यान्वयन है कि मैं के बारे में पता में) एक वर्ग के उदाहरण का आकार बढ़ जाता है, सिवाय इसके कि यदि आप आभासी कार्यों के साथ एक वर्ग से आभासी कार्यों को जोड़ने या वारिस तो आप एक बार की एक के लिए मारा ले वी-टेबल सूचक।

इसके अलावा, के रूप में किसी को सही ढंग से उल्लेख है एक वर्ग के न्यूनतम आकार 1 बाइट है।

कुछ उदाहरण:

// size 1 byte (at least) 
class cls1 
{ 
}; 

// size 1 byte (at least) 
class cls2 
{ 
    // no hit to the instance size, the function address is used directly by calling code. 
    int instanceFunc(); 
}; 

// sizeof(void*) (at least, for the v-table) 
class cls3 
{ 
    // These functions are indirectly called via the v-table, a pointer to which must be stored in each instance. 
    virtual int vFunc1(); 
    // ... 
    virtual int vFunc99(); 
}; 

// sizeof(int) (minimum, but typical) 
class cls4 
{ 
    int data; 
}; 

// sizeof(void*) for the v-table (typical) since the base class has virtual members. 
class cls5 : public cls3 
{ 
}; 

संकलक कार्यान्वयन कई v-तालिका संकेत या अन्य अन्य तरीकों के साथ कई आभासी विरासत संभाल सकता है, तो इन भी वर्ग के आकार पर असर पड़ेगा।

अंत में, सदस्य डेटा संरेखण विकल्पों का असर हो सकता है। कंपाइलर में कुछ विकल्प या #pragma हो सकता है यह निर्दिष्ट करने के लिए कि सदस्य डेटा में एक प्रारंभिक पता होना चाहिए जो निर्दिष्ट बाइट्स की संख्या का एक बहु हो। उदाहरण के लिए, 4 बाइट सीमाओं पर संरेखण और sizeof(int) = 4 संभालने के साथ:

// 12 bytes since the offset of c must be at least 4 bytes from the offset of b. (assuming sizeof(int) = 4, sizeof(bool) = 1) 
class cls6 
{ 
    int a; 
    bool b; 
    int c; 
}; 
+0

करीब, लेकिन खाली प्रकार आमतौर पर कम से कम एक बाइट लेते हैं। कुछ कंपाइलर हैं जो इन्हें एक से कम बाइट बना देंगे। –

+4

@MooingDuck इसे बाइट-एड्रेसेबल मशीनों पर कम से कम एक बाइट होना चाहिए, ताकि दो ऑब्जेक्ट्स का एक ही पता न हो। संकलक निर्णय नहीं लेता है। (स्ट्रॉस्ट्रप ने इसे कहीं लिखा है, जहां मैंने इसे पढ़ा है, हालांकि याद नहीं किया जा सकता है।) –

+0

@ सेठ कार्नेगी: हाँ, लेकिन मानक _also_ कहता है कि संकलक सभी नियमों को तोड़ सकता है जब तक कि यह वही आईओ कॉल और अस्थिर बनाता है उसी पैरामीटर के साथ उसी क्रम में पढ़ें/लिखते हैं, जो जीसीसी को कभी-कभी एक बाइट से कम ऑब्जेक्ट्स बनाने की अनुमति देता है, जब तक कि यह प्रोग्राम के निष्पादन को परिवर्तित नहीं करता है। –

4

स्ट्रिंगली बोलते हुए, यह कार्यान्वयन निर्भर है। लेकिन विधियों की संख्या वर्ग वस्तुओं के आकार को नहीं बदलना चाहिए। गैर वर्चुअल विधियों के लिए, ऑब्जेक्ट मेमोरी के अंदर कुछ भी नहीं है जो विधि पॉइंटर्स से संबंधित है। यदि आपके पास वर्चुअल विधियां हैं, तो प्रत्येक ऑब्जेक्ट में एक vtable के लिए एक पॉइंटर होता है। जब आप अधिक तरीकों को जोड़ते हैं तो vtable बढ़ता है, लेकिन पॉइंटर आकार वही रहता है।

और जानकारी: गैर-वर्चुअल विधियों के लिए, प्रत्येक वर्ग के लिए कंपाइलर ट्रैक पॉइंटर्स ट्रैक करता है। जब आप एक गैर वर्चुअल विधि को कॉल करते हैं, तो संकलक उस विधि को पॉइंटर पास करता है जो ऑब्जेक्ट को इंगित करता है, या तो एक छिपे पैरामीटर के रूप में, या स्टैक पर। इस प्रकार एक विधि 'वस्तु' जानता है और this पॉइंटर तक पहुंच गया है। आभासी तरीकों के लिए, विधि सूचक वास्तव में vtable में एक अनुक्रमणिका है, इसलिए संकलक vtable में dereferenced प्रविष्टि के लिए this पास करता है।

+0

, प्रत्येक वर्ग के लिए संकलक ट्रैक पॉइंटर्स ट्रैक करता है। क्या यह एक व्यापार है जो अंतरिक्ष के लिए बलिदान का समय है? – Djvu

+0

@Djvu, नहीं, गैर-वर्चुअल विधियां दोनों समय और स्थान में अधिक कुशल हैं। – ThomasMcLeod

3

हाँ वे करेंगे। असल में आपके मामले में आकार 1. सी ++ में किसी भी डेटा सदस्य के बिना भी एक वर्ग का आकार होगा।

1

Foo और Bar प्रत्येक एक बाइट होना चाहिए। Derived1 और Derived2 एक या दो बाइट हो सकता है।

कारण संकलक भंडार निष्पादन योग्य कोड में सभी स्थैतिक जानकारी, सभी सदस्य कार्य सहित है। जहाँ आपके कोड Foo का एक उदाहरण पर foo1 कहता है, यह सिर्फ Foo::foo1(this) कहता है, जो कार्यक्रम में हर Foo के लिए ही है। आभासी कार्यों एक अपवाद हैं, लेकिन सदस्य समारोह प्रति अतिरिक्त आकार, केवल एक बार की अतिरिक्त आकार (आमतौर पर 4/8 बाइट्स) में शामिल न करें अगर कोई आभासी कार्यों है बिल्कुल।

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