2016-02-05 7 views
37

से सी ++ कक्षाओं के साथ बातचीत करना मेरे पास सी ++ में लिखे गए वर्गों की एक महत्वपूर्ण लाइब्रेरी है। मैं स्विफ्ट कोड के रूप में उन्हें फिर से लिखने के बजाय स्विफ्ट के भीतर किसी प्रकार के पुल के माध्यम से उनका उपयोग करने की कोशिश कर रहा हूं। प्राथमिक प्रेरणा यह है कि सी ++ कोड कोर लाइब्रेरी का प्रतिनिधित्व करता है जिसका उपयोग एकाधिक प्लेटफॉर्म पर किया जाता है। प्रभावी रूप से, मैं सिर्फ ओएस एक्सस्विफ्ट

के तहत काम करने की अनुमति देने के लिए एक स्विफ्ट आधारित यूआई बना रहा हूं, अन्य प्रश्न पूछ रहे हैं, "मैं स्विफ्ट से सी ++ फ़ंक्शन कैसे कॉल करूं।" यह मेरा प्रश्न है। एक सी ++ कार्य करने के लिए पुल करने के लिए निम्न ठीक काम करता है:

'सी' के माध्यम से एक ब्रिजिंग हैडर परिभाषित

#ifndef ImageReader_hpp 
#define ImageReader_hpp 

#ifdef __cplusplus 
extern "C" { 
#endif 

    const char *hexdump(char *filename); 
    const char *imageType(char *filename); 

#ifdef __cplusplus 
} 
#endif 

#endif /* ImageReader_hpp */ 

कार्यों सीधे

let type = String.fromCString(imageType(filename)) 
let dump = String.fromCString(hexdump(filename)) 

स्विफ्ट कोड अब कॉल कर सकते हैं मेरे प्रश्न अधिक विशिष्ट है। मैं स्विफ्ट के भीतर से सी ++ कक्षा को तत्काल और कुशलतापूर्वक कैसे उपयोग कर सकता हूं? मुझे इस पर प्रकाशित कुछ भी नहीं मिल रहा है।

+4

मैंने व्यक्तिगत रूप से सादा उद्देश्य-सी ++ रैपर फ़ाइलों को लिखने का सहारा लिया है जो एक उद्देश्य-सी वर्ग का पर्दाफाश करते हैं जो सभी प्रासंगिक सी ++ कॉलों को पुन: उत्पन्न करता है और उन्हें सी ++ कक्षा के आयोजित उदाहरण में अग्रेषित करता है। मेरे मामले में सी ++ कक्षाओं और कॉलों की संख्या कम है इसलिए यह विशेष रूप से श्रम गहन नहीं है। लेकिन मैं उम्मीद में एक उत्तर के रूप में वकालत करने पर रोक लगा दूंगा कि कोई बेहतर कुछ के साथ आएगा। – Tommy

+0

अच्छा, यह कुछ है ... चलो प्रतीक्षा करें और देखें (और आशा है)। –

+0

मुझे आईआरसी के माध्यम से एक स्विफ्ट रैपर क्लास लिखने के लिए एक सुझाव प्राप्त हुआ है जो वास्तविक सी ++ ऑब्जेक्ट में एक शून्य सूचक को बनाए रखता है और आवश्यक तरीके से खुलासा करता है जो प्रभावी रूप से सी पुल और ऑब्जेक्ट के पॉइंटर के माध्यम से पारित होता है। –

उत्तर

33

मैंने एक पूरी तरह से प्रबंधित जवाब तैयार किया है। आप इसे कितना साफ करना चाहते हैं यह पूरी तरह से इस बात पर आधारित है कि आप कितना काम करना चाहते हैं।

सबसे पहले, अपनी सी ++ कक्षा लें और इसके साथ इंटरफेस करने के लिए सी "रैपर" फ़ंक्शन बनाएं। उदाहरण के लिए, अगर हम इस सी है ++ वर्ग:

#include "MBR.hpp" 

using namespace std; 
const void * initialize(char *filename) 
{ 
    MBR *mbr = new MBR(filename); 

    return (void *)mbr; 
} 

const char *hexdump(const void *object) 
{ 
    MBR *mbr; 
    static char retval[2048]; 

    mbr = (MBR *)object; 
    strcpy(retval, mbr -> hexdump()); 
    return retval; 
} 

const char *imageType(const void *object) 
{ 
    MBR *mbr; 
    static char retval[256]; 

    mbr = (MBR *)object; 
    strcpy(retval, mbr -> imageType()); 
    return retval; 
} 

पुल हैडर तो शामिल हैं::

class MBR { 
    std::string filename; 

public: 
    MBR (std::string filename); 
    const char *hexdump(); 
    const char *imageType(); 
    const char *bootCode(); 
    const char *partitions(); 
private: 
    bool readFile(unsigned char *buffer, const unsigned int length); 
}; 

हम तो इन सी ++ कार्यों को लागू

#ifndef ImageReader_hpp 
#define ImageReader_hpp 

#ifdef __cplusplus 
extern "C" { 
#endif 

    const void *initialize(char *filename); 
    const char *hexdump(const void *object); 
    const char *imageType(const void *object); 

#ifdef __cplusplus 
} 
#endif 

#endif /* ImageReader_hpp */ 

स्विफ्ट से, अब हम कर सकते हैं ऑब्जेक्ट को तत्काल करें और इसके साथ बातचीत करें:

let cppObject = UnsafeMutablePointer<Void>(initialize(filename)) 
let type = String.fromCString(imageType(cppObject)) 
let dump = String.fromCString(hexdump(cppObject))     
self.imageTypeLabel.stringValue = type! 
self.dumpDisplay.stringValue = dump! 

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

बनाना यह क्लीनर

हालांकि यह एक शानदार शुरुआत है और साबित करता है कि यह एक छोटी सी पुल के साथ मौजूदा सी ++ वर्गों का उपयोग करने के लिए पूरी तरह से संभव है, तो यह और भी क्लीनर हो सकता है।

सफाई करने का मतलब यह होगा कि हम अपने स्विफ्ट कोड के बीच से UnsafeMutablePointer<Void> हटा दें और इसे स्विफ्ट क्लास में समाहित करें। अनिवार्य रूप से, हम एक ही सी/सी ++ रैपर फ़ंक्शंस का उपयोग करते हैं लेकिन उन्हें स्विफ्ट क्लास के साथ इंटरफ़ेस करते हैं। स्विफ्ट क्लास ऑब्जेक्ट रेफरेंस को बरकरार रखती है और अनिवार्य रूप से पुल के माध्यम से सी ++ ऑब्जेक्ट पर सभी विधि और विशेषता संदर्भ कॉल पास करती है!

ऐसा करने के बाद, सभी ब्रिजिंग कोड स्विफ्ट क्लास में पूरी तरह से encapsulated है। भले ही हम अभी भी सी ब्रिज का उपयोग कर रहे हैं, हम उद्देश्य-सी या उद्देश्य-सी ++ में उन्हें रिकोड करने के बिना पारदर्शी रूप से C++ ऑब्जेक्ट्स का उपयोग कर रहे हैं।

+6

यहां कुछ महत्वपूर्ण मिस्ड समस्याएं हैं। पहला यह है कि विनाशक को कभी नहीं कहा जाता है, और वस्तु लीक हो जाती है। दूसरा यह है कि अपवाद कुछ बुरा परेशानी पैदा कर सकता है। –

+0

मैंने इस प्रश्न के उत्तर में मुद्दों का एक समूह शामिल किया है http://stackoverflow.com/questions/2045774/developing-c-wrapper-api-for-object-oriented-c-code/2045860 –

+0

ObjC++ में लपेटना बेहतर तरीका। मेमोरी बेहतर तरीके से संभाली जाती है और आपको पकड़ने और पास करने की आवश्यकता नहीं होती है (शून्य *)। Djinni जैसे टूल का उपयोग करने के लिए ओब्जे-सी इंटरफेस बनाने के लिए विचार करें। –

8

स्विफ्ट में वर्तमान में कोई सी ++ इंटरऑप नहीं है। यह एक दीर्घकालिक लक्ष्य है, लेकिन निकट भविष्य में होने की संभावना बहुत कम है।

+18

कॉलिंग "सी सी ++ इंटरऑप" का एक रूप "कॉलिंग + सी ++ इंटरऑप" का एक रूप है, इस शब्द को काफी –

+2

शब्द खींच रहा है, लेकिन आप उन्हें सी ++ कक्षा को तुरंत चालू करने की अनुमति देने के लिए उपयोग कर रहे हैं और फिर कॉल करने के तरीकों से यह उपयोगी और प्रश्न को संतुष्ट करता है। –

+0

वास्तव में, यह अब दीर्घकालिक लक्ष्य नहीं है, बल्कि इसके बजाय, रोडमैप में "दायरे से बाहर" के रूप में चिह्नित किया गया है। सी-रैपर का उपयोग करके –

4

अपने स्वयं के समाधान के अतिरिक्त, ऐसा करने का एक और तरीका है। आप उद्देश्य-सी ++ में सी ++ कोड को कॉल या सीधे लिख सकते हैं।

तो आप अपने सी ++ कोड के शीर्ष पर एक उद्देश्य-सी ++ आवरण बना सकते हैं और एक उपयुक्त इंटरफेस

बनाते हैं और अपने तेज कोड से उद्देश्य-सी ++ कोड कॉल करते हैं। उद्देश्य-सी ++ कोड लिखने में सक्षम होने के लिए आपको .m से .mm

से फ़ाइल एक्सटेंशन का नाम बदलना पड़ सकता है उपयुक्त होने पर आपके C++ ऑब्जेक्ट्स द्वारा आवंटित स्मृति को मिटाना न भूलें।

1

जैसा कि एक और उत्तर दिया गया है, ओब्जेसी ++ का उपयोग करने के लिए बातचीत करना बहुत आसान है। बस .m और xcode/clang के बजाय अपनी फ़ाइलों का नाम .mm, आपको उस फ़ाइल में C++ तक पहुंच प्रदान करता है।

ध्यान दें कि ओबीजेसी ++ सी ++ विरासत का समर्थन नहीं करता है। मैं ओबीजेसी ++ में सी ++ कक्षा को उप-वर्ग करना चाहता हूं, आप नहीं कर सकते। आपको सी ++ में उप-वर्ग लिखना होगा और उसे ओबीजेसी ++ कक्षा के चारों ओर लपेटना होगा।

फिर ब्रिजिंग हेडर का उपयोग करें जिसका उपयोग आप आमतौर पर ओबीजेसी को स्विफ्ट से कॉल करने के लिए करेंगे।