2011-05-24 10 views
10

मैं आज एक समस्या में ठोकर खाई कि मैं हल नहीं कर सकता। मैं एक साझा लाइब्रेरी संकलित कर रहा हूं जिसमें एक टेम्पलेटेड क्लास (Derived<T>, जिसका आधार Base है) और इस वर्ग के कुछ स्पष्ट तत्कालताएं शामिल हैं। मैं लाइब्रेरी उपयोगकर्ता को इस टेम्पलेटेड क्लास से विस्तार करना चाहता हूं। समस्या तब उत्पन्न होती है जब मैं dynamic_cast उपयोगकर्ता का उदाहरण Base* से Derived<T>* पर करता हूं।एक साझा लाइब्रेरी में एक टेम्पलेटेड क्लास और गतिशील_कास्ट की स्पष्ट तत्कालता

साझा लाइब्रेरी निम्न फ़ाइलें हैं::

Base.h

#ifndef BASE_H_ 
#define BASE_H_ 

class Base { 
public: 
    Base(); 
    virtual ~Base(); 
}; 

#endif /* BASE_H_ */ 

Derived.h

मैं इस मेगावाट करने के लिए समस्या को संकुचित होता है

#ifndef DERIVED_H_ 
#define DERIVED_H_  
#include <Base.h> 

template <typename T> 
class Derived : public Base { 
public: 
    Derived(); 
    virtual ~Derived(); 
}; 

#endif /* DERIVED_H_ */ 
,210

Derived.cpp

#include <Derived.h> 

template <typename T> 
Derived<T>::Derived() : 
    Base() { 
} 

template <typename T> 
Derived<T>::~Derived() { 
} 

// explicit instantiations 
template class Derived<float>; 
template class Derived<double>; 
template class Derived<long double>; 

Helper.h

#ifndef HELPER_H_ 
#define HELPER_H_ 

#include <Base.h> 

class Helper { 
public: 
    Helper(Base* m); 
    virtual ~Helper(); 

}; 

#endif /* HELPER_H_ */ 

Helper.cpp

#include <Helper.h> 
#include <Base.h> 
#include <Derived.h> 

#include <iostream> 

using namespace std; 

Helper::Helper(Base* m) { 

    cout << "after received " << m << endl; 
    cout << "after fom: " << dynamic_cast< Derived<float>* >(m) << endl; 
    cout << "after dom: " << dynamic_cast< Derived<double>* >(m) << endl; 
    cout << "after ldom: " << dynamic_cast< Derived<long double>* >(m) << endl; 
    cout << "===" << endl; 
} 

Helper::~Helper() { 
} 

और एक सरल कोड का उपयोग करता है पुस्तकालय हो सकता है:

test.cpp

#include <Derived.h> 
#include <Helper.h> 

#include <iostream> 

using namespace std; 

class MyModel : public Derived<double> { 
public: 
    MyModel() : Derived<double>() { 
    }; 

    virtual ~MyModel() { 
    };   

}; 

int main(int argc, char *argv[]) { 

    MyModel om1; 
    cout << "created mymodel " << &om1 << endl; 
    cout << "before fom: " << dynamic_cast< Derived<float>* >(&om1) << endl; 
    cout << "before dom: " << dynamic_cast< Derived<double>* >(&om1) << endl; 
    cout << "before ldom: " << dynamic_cast< Derived<long double>* >(&om1) << endl; 
    cout << "===" << endl; 
    Helper root(&om1); 

    return 0; 
} 

समस्या यह है कि जब मैं एक शेयर की गई लाइब्रेरी और इसके खिलाफ कड़ी test.cpp बनाने के लिए, dynamic_cast विफल रहता है।

created mymodel 0x7fff5fbff3e0 
before fom: 0 
before dom: 0x7fff5fbff3e0 
before ldom: 0 
=== 
after received 0x7fff5fbff3e0 
after fom: 0 
after dom: 0 // <<< Here I expected it to succeed and return a non-null pointer 
after ldom: 0 
=== 

, अगर मैं एक साथ पूरे पुस्तकालय और उदाहरण संकलन, कलाकारों सफल होता है हालांकि:

created mymodel 0x7fff5fbff3e0 
before fom: 0 
before dom: 0x7fff5fbff3e0 
before ldom: 0 
=== 
after received 0x7fff5fbff3e0 
after fom: 0 
after dom: 0x7fff5fbff3e0 
after ldom: 0 
=== 

मेरा प्रश्न है: क्यों dynamic_cast में नाकाम रहने के है यहाँ एक उदाहरण उत्पादन है?

और, इस आधार पर कि मैं उदाहरण की तरह एक वर्ग संरचना को बनाए रखना चाहता हूं, और साझा लाइब्रेरी का उपयोग करना जारी रखता हूं: मैं से Derived<some type>* कास्ट सफलतापूर्वक कैसे प्राप्त कर सकता हूं?

+0

इसे कम करने के लिए सुझाव ... 1) पूरी तरह से सुनिश्चित करें कि आपके कंपाइलर को पास किए गए विकल्प आपके प्रोग्राम घटकों के लिए आपके lib घटकों के लिए समान हैं ... वे मनग्रस्त प्रतीकों को प्रभावित कर सकते हैं। 2) '[nm] (http://linux.about.com/library/cmd/blcmdl1_nm.htm)' टूल का उपयोग अपनी लाइब्रेरी ऑब्जेक्ट्स और प्रोग्राम प्रोग्राम दोनों से प्रतीकों को डंप करने के लिए करें ... आपको वही देखना चाहिए आपके लाइब्रेरी घटक (परिभाषित) और आपके टेस्ट कोड (अपरिभाषित) के लिए उलझन वाले प्रतीक – Andrew

उत्तर

3

मुझे लगता है कि आप लिनक्स/जीसीसी पर हैं, क्योंकि विंडोज़ पर इसे "बस काम करना चाहिए"।

यह जीसीसी के साथ "बस काम नहीं करता" है, क्योंकि प्रदर्शन के लिए जीसीसी में आरटीटीआई समर्थन पॉइंटर तुलना पर निर्भर करता है। यह सब this GCC FAQ में समझाया गया है, जिसमें इसे हल किया जा सकता है। संपादित करें: हालांकि, यह अक्सर पूछे जाने वाले प्रश्न यह कहते हैं कि यह dlopen() के साथ काम नहीं करता है जबकि साझा लाइब्रेरी के साथ स्पष्ट लिंक करना चाहिए; तो शायद कुछ और है, जैसे नीचे वर्णित बग।

कुछ अन्य लिंक मैंने पाया कि सहायक हो सकता है:
dynamic_cast an interface from a shared library which was loaded by lt_dlopen(libtool) doesn't work
dynamic cast with interfaces
C++ dynamic_cast bug in Mac OS 10.6 Snow Leopard

+0

मै मैक के तहत जीसीसी का उपयोग कर रहा हूं, मैंने अभी तक लिनक्स/जीसीसी की कोशिश नहीं की है। मैं आपके लिंक को देख लूंगा। – YuppieNetworking

+0

मैंने कल रात लिनक्स/जीसीसी 4.4.5 और 4.5.2 के साथ कोशिश की और यह बॉक्स से बाहर काम किया। मैक ओएसएक्स/जीसीसी 4.2.1 पर यह नहीं था। मैक पर इसे हल करने के लिए, मैंने आपके लिंक का पालन किया और '-mmacosx-version-min = 10.4' विकल्प का उपयोग किया। आश्चर्यजनक रूप से, '-Wl, -no_compact_linkedit' ध्वज मेरे लिए काम नहीं करता था, लेकिन मेरा मानना ​​है कि यह शायद सीएमके अपने कंपाइलर/लिंकर झंडे को कैसे संभालता है। मैं अभी भी परीक्षण करने के लिए जीसीसी 4.2.1 के साथ एक * पुरानी * लिनक्स मशीन की तलाश में हूं। आपकी मदद के लिए धन्यवाद – YuppieNetworking

4

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

मेरे अनुभव में, जिन मामलों में आरटीटीआई साझा-पुस्तकालय सीमाओं के बीच पार नहीं हो सकता है, वे मामलों के मुकाबले कहीं अधिक हैं।

समाधान है या तो:

  • (इस समाधान का प्रबंधन करने के लिए बहुत कठिन है) साझा-पुस्तकालय कोड जहां dynamic_cast प्रयोग किया जाता है के भीतर करने के लिए इन व्युत्पन्न प्रकार से वस्तुओं के सभी निर्माणों को सीमित करें।

  • गतिशील_कास्ट का उपयोग न करें (यह समाधान आदर्शवादी है, शायद ही कभी लागू है)।

  • साझा-पुस्तकालयों का उपयोग न करें (मूल्यांकन करें कि साझा-पुस्तकालय वास्तव में आपको क्या चाहिए, या शायद, आपके साझा-पुस्तकालय से उच्च-स्तरीय इंटरफ़ेस का पर्दाफाश करें, जो पॉलिमॉर्फिक प्रकारों को व्युत्पन्न नहीं करता है (जो ऐसा लगता है कि आपके आवेदन में "खुली वास्तुकला" अधिक उपयुक्त है)।

  • अपनी खुद की आरटीटीआई प्रणाली और कास्टिंग ऑपरेटर परिभाषित करें (यह आपके कौशल के आधार पर कठिन हो सकता है, लेकिन यह बहुत अधिक कोड नहीं है, और कई मुख्य धारा परियोजनाएं इस समाधान का उपयोग करती हैं और आप बहुत सारे उदाहरण पा सकते हैं यह कैसे करें)।

+0

क्या आप मुख्य-स्ट्रीम परियोजनाओं के कुछ उदाहरण उद्धृत कर सकते हैं जो अपनी स्वयं की आरटीटीआई प्रणाली को परिभाषित करते हैं? – YuppieNetworking

+1

एलएलवीएम, बूस्ट। सीरियलाइजेशन, क्यूटी और वीसीएल/सीएलएक्स, डीनओबीजे और मेरी अपनी परियोजनाओं (जो मुख्य धारा नहीं है) जैसे अधिकांश जीयूआई उपकरण। –

+0

धन्यवाद माइकल। मैं उस अंतिम विकल्प पर गंभीरता से विचार कर रहा हूं ... मुझे पहले कुछ रातों के लिए अपने तकिए से जांच करनी होगी। – YuppieNetworking

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