2014-07-03 6 views
5

आरटीटीआई के बिना और आभासी कार्यों के साथ। आभासी विधि कॉल के साथसी ++ ऑब्जेक्ट का भंडारण प्रकार, कौन सी पसंद बेहतर है?

और विधि के अंदर आईडी रखें::

class Base { 
public: 
virtual ~Base(); 
virtual int getType() const =0; 
}; 
class Derived : public Base { 
public: 
virtual int getType() const { return DerivedID; } 
}; 
इनलाइन विधि कॉल के साथ

और आधार वर्ग में आईडी रखने

मैं 2 अलग सामान्य समाधान वस्तु के प्रकार प्रदान करने के लिए का सामना करना पड़ा :

class Base { 
int id_; 
public: 
virtual ~Base(); 
inline int getType() const { return id_; } 
}; 

class Derived : public Base { 
public: 
    Derived() { id_=DerivedID;} 
}; 

सामान्य रूप से बेहतर विकल्प क्या होगा और उनमें से कौन सा समर्थक होगा?

+6

यदि आप दूसरा चुनते हैं, तो बेस के संरक्षित कन्स्ट्रक्टर को आईडी को तर्क के रूप में ले जाएं - फिर कम से कम इसे हमेशा प्रारंभ किया जाएगा और कार्यान्वयनकर्ता इसे – stijn

+0

इंटरफ़ेस के साथ चिपकाने के लिए मजबूर होंगे! –

उत्तर

1

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

+0

का खुलासा नहीं करता है क्या आप 'वर्चुअल' फ़ंक्शन को विचाराधीन करने के रनटाइम ओवरहेड लेते हैं? या वास्तविक जीवन अनुप्रयोगों में यह बहुत छोटा है? पसंद मुझे पसंद करता है जैसे _extra रनटाइम स्टोरेज बनाम अतिरिक्त रनटाइम प्रोसेसिंग _... –

+0

@ वर्चुअल फ़ंक्शन के ओवरहेड @ ड्रूडॉर्मन छोटे और सामान्य दोनों हैं, इसलिए मैंने ज्यादातर समय इसके बारे में चिंता करना बंद करना सीखा है। लेकिन तुम सही हो –

+0

'vtable में एक अतिरिक्त सूचक जो प्रति वर्ग एक बार मौजूद है, प्रति ऑब्जेक्ट नहीं' सादा गलत लगता है –

0

आप सभी

struct Interface { 
    virtual void foo() = 0; 
    virtual int bar() = 0; 
}; 

template<class T> 
class Base : public Interface { 
public: 
    int getType() const { return getTypeId(); } 
    static int getTypeId() { return T::ClassId; } 
}; 

class Derived : public Base<Derived> { 
public: 
    static const int ClassId = DerivedID; 

    virtual void foo() { } 
    virtual int bar() { return 1; } 

}; 

प्रयोग पर इस सुविधा का समर्थन करने के लिए तत्काल आधार वर्ग, या किसी भी आधार वर्ग सदस्य चर से आभासी विरासत की आवश्यकता नहीं है

Derived der; 
Interface* iface = &der; 
iface->foo(); 
iface->bar(); 

की तरह काम कर रहे नमूना देखें here

नोट:
प्रकार आप इस तरह के सिस्टम की मौजूदा विन्यास के साथ उपयोग किए जाने वाले सभी अच्छी तरह से संकलन समय पर जाना जाने की जरूरत है। यह Plugin pattern based तंत्र का समर्थन नहीं करता है।

+1

मुझे लगता है कि एक सामान्य आधार वर्ग में मौजूद 'getType() 'के विचार को तोड़ता है, है ना? –

+0

@DrewDormann यदि आवश्यक हो तो भी आप एक vtable पेश कर सकते हैं। लेकिन जैसा ओपी आरटीटीआई के बिना राज्य करता है वैसे भी यह बेकार हो सकता है। मुझे विश्वास नहीं है कि 'dynamic_cast <>()' आधारित डिज़ाइन वास्तव में कुछ भी अच्छा होता है। –

+0

यदि आपके पास बेस क्लास के पॉइंटर या संदर्भ हैं, तो आप उचित व्युत्पन्न आईडी कैसे वापस कर रहे हैं? सीआरटीपी संकलन-समय बहुरूपता के लिए है, रन-टाइम नहीं। –

0

ठीक है, मैं एक चाकू ले लेंगे ...

"क्या हैं पेशेवरों/उनमें से विपक्ष?"

आपका पहला उदाहरण virtual int getType() const =0; पड़ता अतिरिक्त संसाधन भूमि के ऊपर। एक सीपीयू के लिए virtual फ़ंक्शन कॉल अधिक कठिन हो सकता है। This issue may be trivial

आपका दूसरा उदाहरण inline int getType() const { return id_; }अतिरिक्त रनटाइम स्टोरेज शामिल करता है। और अतिरिक्त int प्रत्येक Base के प्रत्येक उदाहरण के लिए संग्रहीत किया जाता है। यह भी मामूली हो सकता है।

"सामान्य रूप से बेहतर विकल्प क्या होगा?"

सामान्य रूप से, समयपूर्व अनुकूलन से बचें। बेस क्लास में शुद्ध वर्चुअल फ़ंक्शन चुनें, क्योंकि इसकी शुद्धता संकलक और रनटाइम द्वारा लागू की जाती है।

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