2017-07-14 9 views
5

दौरान बदलने का प्रकार मैं सिर्फ निम्नलिखित व्यवहार discoverd: प्रकार B प्रकार A से प्राप्त की एक वस्तु हो रही है, A के निर्माण के दौरान अंतिम प्रकार A और नहीं B है। यह निम्न उदाहरण के साथ मनाया जा सकता है:एक वस्तु निर्माण

#include <iostream> 
#include <typeinfo> 

class A 
{ 
    public: 
     A() { std::cout << &typeid(*this) << std::endl; } 
}; 

class B : public A 
{ 
    public: 
     B() : A() { std::cout << &typeid(*this) << std::endl; } 
}; 

int main() 
{ 
    A a; 
    B b; 
    return 0; 
} 

इस कोड (जीसीसी 4.8.5 के साथ संकलित) के एक रन निम्नलिखित है:

0x400ae0 
0x400ae0 
0x400ac0 

हम देख सकते हैं कि प्रकार में typeid द्वारा लौटाए गए A::A()A है और B नहीं है, और फिर अंतिम प्रकार B बनने के लिए बदल जाता है।

क्यों?

क्या माता-पिता वर्ग के निर्माण के दौरान "असली" अंतिम प्रकार जानना संभव है?

मैं एक माता पिता के वर्ग Resource और कई वर्गों यह से इनहेरिट है:

मेरे संदर्भ निम्नलिखित है। मेरे पास संसाधन के प्रत्येक निर्माण द्वारा अधिसूचित ResourceManager भी है, और बनाए गए संसाधन के अंतिम प्रकार को जानना है। क्या मैं डुप्लिकेट किए गए कोड से बचने के लिए कर रहा हूँ निम्नलिखित है, लेकिन यह काम नहीं करता है:

class Resource 
{ 
    public: 
    Resource() { ResourceManager::notifyCreation(*this); } 
    ~Resource() { ResourceManager::notifyDestruction(*this); } 
}; 
class MyResource : public Resource 
{ 
    // I don't have to care to the manager here 
}; 

मैं जानता हूँ कि मैं एक निर्माता में बच्चों के/नाशक अधिसूचना कर सकते हैं, लेकिन यह कम मजबूत है (संभव बग यदि प्रबंधक को अधिसूचना के बिना संसाधन को तत्काल किया जाता है)। क्या आपके पास कामकाज के लिए कोई विचार है?

+2

उम्म ... 'और टाइपिड (....)' ?? – WhiZTiM

+3

'* यह 'ए' में हमेशा' ए' है, आप 'टाइपिड' अलग होने की अपेक्षा क्यों करते थे? –

+0

@WhiZTiM क्यों? टाइपिड का रिटर्न वैल्यू प्रत्येक प्रकार के लिए मेमोरी में अद्वितीय है। – Caduchon

उत्तर

5

ध्वनि क्या आप के लिए देख रहे हैं की तरह CRTP

template<typename Concrete> 
struct Resource 
{ 
    Resource() { ResourceManager::notifyCreation(*static_cast<Concrete*>(this)); } 
    ~Resource() { ResourceManager::notifyDestruction(*static_cast<Concrete*>(this)); } 
}; 

struct MyResource : Resource<MyResource> 
{ 

}; 

ध्यान दें कि MyResource नहीं है अभी तक का निर्माण जब notifyCreation करने के लिए कॉल किया जाता है समाप्त हो गया। MyResource उदाहरण का पता लिया जा सकता है, लेकिन यह सब कुछ है जो उदाहरण के लिए किया जा सकता है। से [class.cdtor]

(इस ओर इशारा करते हुए के लिए Caleth के लिए धन्यवाद)

विशेष रूप से typeid के संकार्य निर्माण या विनाश और संकार्य के स्थिर प्रकार के तहत वस्तु को संदर्भित करता है, तो है न निर्माता या नाशक की क्लास न ही इसके अड्डों में से एक, व्यवहार अपरिभाषित है।

इसलिए ResourceManager कुछ इस तरह लागू किया जाना typeid

struct ResourceManager 
{ 
    template<typename T> 
    void notifyCreation(T&&) 
    { 
     add(typeid(T)); // can't apply to an expression 
    } 
    template<typename T> 
    void notifyDestruction(T&&) 
    { 
     remove(typeid(T)); // can't apply to an expression 
    } 
}; 
+0

यह केवल तभी सुरक्षित है जब 'माइक्रोसॉर्स' के पास 'संसाधन' – Caleth

+1

@ कैलेथ से परे कोई सदस्य नहीं है, तो आपका मतलब कोई और कक्षा नहीं है? हां, लेकिन कोड ओपी दिखाया गया है इस तरह दिखता है और मैं यह अनुमान लगाने के लिए नहीं चला कि ओपी क्या चाहता है ओपी –

+0

नहीं, मेरा मतलब है कि कोई और डेटा सदस्य नहीं है। उन्हें उस बिंदु पर शुरू नहीं किया गया है जहां 'संसाधन प्रबंधक :: अधिसूचनाकरण' कहा जाता है, और जब संसाधन संसाधन :: अधिसूचना निर्देश 'को – Caleth

1

अपने उदाहरण के रूप में एक निर्माता में यह करने के लिए कोई अच्छा तरीका नहीं है का उपयोग कर सक्षम करने के लिए होता है, लेकिन आप एक विशेष निर्माता प्रदान कर सकते हैं A, यानी के लिए

A(const std::type_info &info) { 
    std::cout << info.name() << std::endl; 
} 

और B

B() : A(typeid(*this)) { 
    std::cout << typeid(*this).name() std::endl; 
} 

में यदि आप इसे निर्माता के बाहर करते हैं, आप भी 'ए' में एक आभासी समारोह प्रदान करते हैं और 'बी' में यह ऊपर लिख सकते हैं।

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