ObjectScript API, C ++ के साथ एकीकरण। भाग 4: C ++ में कस्टम कक्षाओं और कार्यों को जोड़ना

ObjectScript एक नया, ओपन सोर्स, ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग लैंग्वेज है। ObjectScript जावास्क्रिप्ट, लुआ और PHP जैसी भाषाओं की क्षमताओं का विस्तार करता है।

पिछले लेखों के परिणामों के आधार पर, आपके सी ++ वर्गों और कार्यों को ऑब्जेक्टस्क्रिप्ट से कैसे जोड़ा जाए, इसके बारे में कई सवाल थे। पहले ओएस में उपलब्ध कनेक्शन विधि शायद ही जरूरतों को पूरा करती है, और मैंने अधिक शक्तिशाली और सुविधाजनक बंधन बनाने का फैसला किया, जो अब डिफ़ॉल्ट ओएस के साथ आता है।

नए बंधन का वास्तविक लाभ क्या है: अब आप किसी भी फ़ंक्शन को किसी भी पैरामीटर, अतिरिक्त रैपर के बिना किसी भी रिटर्न मान से जोड़ सकते हैं। उस फ़ंक्शन को तुरंत कनेक्ट करें जो आपके पास है और सब कुछ तैयार है। और सुनिश्चित करें कि जब आप ओएस पर एक स्क्रिप्ट से C ++ फ़ंक्शन को कॉल करते हैं, तो यह सही पैरामीटर प्राप्त करेगा, और C ++ से लौटाए गए मान को ओएस पर एक एनालॉग में सही ढंग से परिवर्तित किया जाएगा।

भाग 4: C ++ में कस्टम कक्षाओं और कार्यों का बंधन


भाग 3 में , एक निम्न-स्तरीय कनेक्शन विधि का वर्णन किया गया था, इसे संरक्षित किया गया था। नई विधि किसी भी पैरामीटर, किसी भी रिटर्न वैल्यू के साथ फ़ंक्शन को जोड़ने के जादू को लागू करती है। तो चलिए!

एक वैश्विक कार्य को जोड़ना


मान लीजिए कि C ++ में हमारे पास निम्न कार्य है:

std::string getcwdString() { const int PATH_MAX = 1024; char buf[PATH_MAX]; getcwd(buf, PATH_MAX); return buf; } 

इसे ओएस पर वैश्विक नामस्थान से जोड़ने के लिए, आपको कोड चलाने की आवश्यकता है:

 os->setGlobal(def("getcwd", getcwdString)); 

ObjectScript से फ़ंक्शन को कॉल करें:

 print "getcwd: "..getcwd() 

निष्कर्ष:

 getcwd: C:\Sources\OS\proj.win32\osbind 

फ़ंक्शन के साथ एक मॉड्यूल कनेक्ट करना


मान लें कि हमारे पास C ++ में निम्नलिखित कार्य हैं (ध्यान दें कि फ़ंक्शन स्वीकार करते हैं और पूरी तरह से अलग डेटा प्रकार लौटाते हैं):

 bool my_isdigit(const OS::String& str) { int len = str.getLen(); for(int i = 0; i < len; i++){ if(!isdigit(str[i])){ return false; } } return len > 0; } std::string my_hash(const char * str) { int i, len = strlen(str), hash = 5381; for(i = 0; i < len; i++){ hash = ((hash << 5) + hash) + str[i]; } hash &= 0x7fffffff; char buf[16]; for(i = 0; hash > 0; hash >>= 4){ buf[i++] = "0123456789abcdef"[hash & 0xf]; } buf[i] = 0; return buf; } void my_print_num(int i) { printf("my_print_num: %d\n", i); } void my_print_void(void) { printf("my_print_void\n"); } long double my_fabs(long double a) { return a >= 0 ? a : -a; } 

बेशक, उपयोगकर्ता-परिभाषित फ़ंक्शन कई पैरामीटर ले सकते हैं। हम अपने मॉड्यूल के रूप में OS से फ़ंक्शंस कनेक्ट करते हैं:

 OS::FuncDef funcs[] = { def("isdigit", my_isdigit), def("hash", my_hash), def("print_num", my_print_num), def("print_void", my_print_void), def("abs", my_fabs), {} }; os->getModule("my"); os->setFuncs(funcs); os->pop(); 

किया, अब वे ओएस पर इस्तेमाल किया जा सकता है:

 print "isdigit(123): "..my.isdigit("123") print "isdigit(123q): "..my.isdigit("123q") print "my.hash(123): "..my.hash(123) print "call my.print_num(123.5)" my.print_num(123.5) print "call my.print_void()" my.print_void() print "my.abs(-12): "..my.abs(-12) print "my.fabs(-123.5): "..my.fabs(-123.5) 

निष्कर्ष:

 isdigit(123): true isdigit(123q): false my.hash(123): bf9878b call my.print_num(123.5) my_print_num: 123 call my.print_void() my_print_void my.abs(-12): 12 my.fabs(-123.5): 123.5 

सी ++ वर्ग कनेक्शन


यहां मस्ती शुरू होती है। मान लें कि हमारे पास निम्न C ++ परीक्षण वर्ग है जिसे हम OS कोड में उपयोग करना चाहते हैं:

 class TestClass { public: int i; float j; TestClass(int _i, float _j){ i = _i; j = _j; } int getI() const { return i; } void setI(int _i){ i = _i; } float getJ() const { return j; } void setJ(float _j){ j = _j; } double doSomething(int a, float b, double c, TestClass * pb) { return i + j + a + b + c + pb->i + pb->j; } void print() { printf("test class: %d, %f\n", i, j); } }; 

OS से कनेक्ट करें:

 // 1.       ObjectScript // OS_DECL_USER_CLASS -  ,     //        C++ namespace ObjectScript { OS_DECL_USER_CLASS(TestClass); } // 2.   ,      TestClass * __constructTestClass(int i, float j){ return new TestClass(i, j); } // 3.        OS OS::FuncDef funcs[] = { def("__construct", __constructTestClass), def("__get@i", &TestClass::getI), def("__set@i", &TestClass::setI), def("__get@j", &TestClass::getJ), def("__set@j", &TestClass::setJ), def("doSomething", &TestClass::doSomething), def("print", &TestClass::print), {} }; registerUserClass<TestClass>(os, funcs); 

हो गया, OS पर जांचें:

 var t = TestClass(1, 0.25) print "ti: "..ti print "tj: "..tj var t2 = TestClass(2, 0.5) t2.i = t2.i + tj print "t2" t2.print() print "t.doSomething(10, 100.001, 1000.1, t2): "..t.doSomething(10, 100.001, 1000.1, t2) 

निष्कर्ष:

 ti: 1 tj: 0.25 t2 test class: 2, 0.500000 t.doSomething(10, 100.001, 1000.1, t2): 1113.8509994506835 

यह काम करता है! इस लेख के स्रोत कोड में, आपको यह भी पता चलेगा कि कस्टम क्लास को कैसे क्लोन किया जाए और गणितीय ऑपरेटरों को अधिभारित किया जाए।

C ++ में एक कस्टम डेटा प्रकार कनेक्ट करना


खैर, शुरुआत के लिए, मान लें कि हमारे पास C ++ में एक डेटा संरचना है और हम चाहते हैं कि यह ओएस पर मानों के साथ एक कंटेनर के रूप में दिखे।

 struct TestStruct { float a, b; TestStruct(){ a = b = 0; } TestStruct(float _a, float _b){ a = _a; b = _b; } }; void printTestStruct(const TestStruct& p) { printf("TestStruct: %f %f\n", pa, pb); } TestStruct changeTestStruct(const TestStruct& p) { return TestStruct(pa*10, pb*100); } 

आइए हमारी संरचना के साथ काम करने के लिए ओएस को सिखाएं (इसे पैरामीटर के रूप में पास करें और परिणाम वापस करें):

 namespace ObjectScript { OS_DECL_USER_CLASS(TestStruct); template <> struct CtypeValue<TestStruct> { // type   OS typedef TestStruct type; //  true,    C++      static bool isValid(const TestStruct&){ return true; } //       OS,   def static TestStruct def(ObjectScript::OS * os){ return TestStruct(0, 0); } //     OS static TestStruct getArg(ObjectScript::OS * os, int offs) { if(os->isObject(offs)){ os->getProperty(offs, "a"); // required float a = os->popFloat(); os->getProperty(offs, "b"); // required float b = os->popFloat(); return TestStruct(a, b); } os->triggerError(OS_E_ERROR, "TestStruct expected"); return TestStruct(0, 0); } //  OS      TestStruct static void push(ObjectScript::OS * os, const TestStruct& p) { os->newObject(); os->pushStackValue(); os->pushNumber(pa); os->setProperty("a"); os->pushStackValue(); os->pushNumber(pb); os->setProperty("b"); } }; } // namespace ObjectScript 

हम वैश्विक OS नामस्थान में TestStruct के साथ काम करने के लिए C ++ में कार्य पंजीकृत करते हैं:

 os->setGlobal(def("printTestStruct", printTestStruct)); os->setGlobal(def("changeTestStruct", changeTestStruct)); 

OS में जांचें:

 var data = {a=10 b=20} printTestStruct(data) data = changeTestStruct(data) printTestStruct(data) print data 

निष्कर्ष:

 TestStruct: 10.000000 20.000000 TestStruct: 100.000000 2000.000000 {"a":100,"b":2000} 

महान, सब कुछ काम करता है! सभी सरल डेटा प्रकार (फ्लोट, इंट, आदि) पहले से ही उसी तरह से CtypeValue के माध्यम से ओएस पर वर्णित हैं। यदि आपको विशिष्ट डेटा प्रकार रूपांतरण OS -> C ++ और इसके विपरीत वर्णन करने की आवश्यकता है, तो CtypeValue का उपयोग करें।

आप इस लिंक पर ऑब्जेक्टस्क्रिप्ट स्रोत कोड और इस लेख से एक उदाहरण डाउनलोड कर सकते हैं, खोलें proj.win32 \ example.sln , ओस्बिंद परियोजना।

ObjectScript के बारे में अन्य प्रासंगिक लेख:

Source: https://habr.com/ru/post/In154221/


All Articles