上一篇在這 C++混合編程之idlcpp教程Lua篇(5)html
第一篇在這 C++混合編程之idlcpp教程(一)程序員
工程LuaTutorial4中加入了四個文件:LuaTutorial4.cpp, Tutorial4.cpp, Tutorial4.i, tutorial4.lua。這個作法和之前不太同樣,前幾個工程中用.i文件生成的頭文件時,類型的成員函數都是用內聯的方式寫在頭文件中。實際上按C++的使用習慣來講只有簡短的函數建議之內聯方式實現,其他的函數通常寫在另外一個對應的.cpp文件中。此處加入的Tutorial4.cpp就是這個用法。編程
首先看一下Tutorial4.i的內容:數組
#import "../../paf/src/pafcore/Reference.i" ###include <vector> namespace tutorial { struct Point { float x; float y; Point(); Point(float a, float b); nocode Point(const Point& pt); }; class Shape : Reference { abstract float getArea(); ## virtual ~Shape() {} }; class ShapeManager(value_object) { void addShape(Shape* shape); float getTotalArea(); static ShapeManager* GetInstance(); #{ ~ShapeManager(); private: std::vector<Shape*> m_shapes; #} }; class Triangle : Shape { Point m_vertices[#3]; nocode Triangle(); ## virtual float getArea(); }; }
首先是 多線程
#import "../../paf/src/pafcore/Reference.i"編程語言
#import至關於C++中的 #include 編譯時先將其所描述的文件中的內容插入到對應的位置。函數
第二行 post
###include <vector>this
將#include <vector> 插入到Tutorial4.h的對應位置上。lua
在這裏仍然有struct Point,但因爲其中構造函數的實現代碼將會放到Tutorial4.cpp中。因此寫法和之前有所不一樣。
而後是
class Shape : Reference
對照一下上一節的寫法 struct Shape 有兩處不一樣,一是使用了關鍵字class 替代了struct 二是使用了基類Reference。這個基類是運行時庫pafcore提供的,具體內容請參看 Reference.i。class Reference 位於 namespace pafcore下。
許多編程語言對於內存管理都提供了內置的支持,C#,Java,Lua,Python等都有垃圾收集機制,然而在C++中沒有這種機制,通常須要程序員手工維護對象的生命期。一種經常使用的方法是引用計數,引用計數算是一種簡潔高效的手段了。在idlcpp中提供了引用計數的直接支持。類 ::pafcore::Reference 提供了用於引用計數的基本接口。而關鍵字class 默認其描述的類型直接或間接派生自::pafcore::Reference,使用struct 則沒有這個假設,注意此處和C++不一樣。另外若是在idlcpp中使用struct ,則在生成的C++類型中也使用struct 作關鍵字;若是在idlcpp中使用class ,則在生成的C++類型中也使用class 作關鍵字。若是想在C++中使用關鍵字class 且又不想讓其派生自::pafcore::Reference,idlcpp提供了相應的語法來處理這種狀況,見下表:
idlcpp |
C++ |
struct A |
struct A |
class A |
class A : public ::pafcore::Reference |
struct A(reference_object) |
struct A : public ::pafcore::Reference |
class A(value_object) |
class A |
而後是
class ShapeManager(value_object)
如前所述,但願在C++中使用class關鍵字而又不須要派生自::pafcore::Reference,在類型的名字後面加上(value_object)便可。
在class ShapeManager提供了三個接口函數。第一個函數void addShape(Shape ptr shape);在其參數中出現了關鍵字ptr。這個至關於C++中的*,表示傳指針,之因此不使用*而使用ptr代替的緣由見上一節。idlcpp在函數聲明的參數傳遞類型部分有以下幾種形式:
idlcpp聲明 |
C++聲明 |
實現 |
typeName |
typeName |
輸入參數,傳值 |
typeName * |
typeName * |
輸入參數,傳地址 |
typeName & |
typeName & |
輸入參數,傳引用 |
typeName ** |
typeName ** |
輸出參數,傳指針的地址,用於接收要返回的指針 |
typeName ^* |
typeName ** |
輸出參數,傳指針的地址,用於接收函數內部new的對象,或者增長引用計數,外界須要delete或release |
typeName ^[] * |
typeName ** |
輸出參數,傳指針的地址,用於接收函數內部new []的對象數組,外界須要delete [] |
typeName *& |
typeName *& |
輸出參數,傳指針的引用,用於接收要返回的指針 |
typeName ^& |
typeName *& |
輸出參數,傳指針的引用,用於接收函數內部new的對象,或者增長引用計數,外界須要delete或release |
typeName ^[] & |
typeName *& |
輸出參數,傳指針的引用,用於接收函數內部new []的對象數組,外界須要delete [] |
最後的
class Triangle : Shape
和上一節同樣,只不過Shape派生自::pafcore::Reference;所以class Triangle 也有引用計數的功能。
編譯後生成的Tutorial4.h的內容以下:
//DO NOT EDIT THIS FILE, it is generated by idlcpp //http://www.idlcpp.org #pragma once #include "../../paf/src/pafcore/Typedef.h" #include "../../paf/src/pafcore/Reference.h" #include <vector> namespace tutorial { struct Point { public: float x; float y; Point(); Point(float a,float b); }; class Shape : public pafcore::Reference { public: static ::pafcore::ClassType* GetType(); virtual ::pafcore::ClassType* getType(); virtual size_t getAddress(); virtual float getArea() = 0 ; virtual ~Shape() {} }; class ShapeManager { public: void addShape(Shape* shape); float getTotalArea(); static ShapeManager* GetInstance(); ~ShapeManager(); private: std::vector<Shape*> m_shapes; }; class Triangle : public Shape { public: static ::pafcore::ClassType* GetType(); virtual ::pafcore::ClassType* getType(); virtual size_t getAddress(); Point m_vertices[3]; virtual float getArea(); }; }
在類型 Shape 和Triangle中,idlcpp爲其添加了靜態函數
static ::pafcore::ClassType* GetType();
和兩個虛函數
virtual ::pafcore::Type* getType();
virtual size_t getAddress();
Reference 的派生類會自動生成這兩個虛函數,實現代碼見Tutorial4.ic。
下面是Tutorial4.ic的內容
其間的區別見具體實現代碼,實現代碼在Tutorial4.ic中。
下面是Tutorial4.ic的內容
//DO NOT EDIT THIS FILE, it is generated by idlcpp //http://www.idlcpp.org #pragma once #include "Tutorial4.h" #include "Tutorial4.mh" #include "../../paf/src/pafcore/RefCount.h" namespace tutorial { ::pafcore::ClassType* Shape::GetType() { return ::RuntimeTypeOf<Shape>::RuntimeType::GetSingleton(); } ::pafcore::ClassType* Shape::getType() { return ::RuntimeTypeOf<Shape>::RuntimeType::GetSingleton(); } size_t Shape::getAddress() { return (size_t)this; } ::pafcore::ClassType* Triangle::GetType() { return ::RuntimeTypeOf<Triangle>::RuntimeType::GetSingleton(); } ::pafcore::ClassType* Triangle::getType() { return ::RuntimeTypeOf<Triangle>::RuntimeType::GetSingleton(); } size_t Triangle::getAddress() { return (size_t)this; } }
在元數據文件中對應的 Triangle 類型除了實現New()函數外,還有NewARC()函數,一樣也返回一個 new 的 Triangle 指針,二者不一樣之處以下所述。
在::pafcore::Reference中僅僅提供了引用計數的接口,引用計數的具體實現方法是多種多樣的,pafcore中提供的一種實現方法。具體參見pafcore中的文件RefCount.h。其中提供了兩個模板類RefCountObject和AtomicRefCountObject。其中AtomicRefCountObject用原子操做處理引用計數,可用於多線程同時訪問對象引用計數的狀況。在idlcpp生成的New函數和NewARC函數中分別使用了這兩個模板類,用戶能夠根據具體狀況調用不一樣的函數。
再看一下Tutorial4.cpp的內容
#include "Tutorial4.h" #include "Tutorial4.mh" #include "Tutorial4.ic" #include "Tutorial4.mc" namespace tutorial { Point::Point() {} Point::Point(float a, float b) { x = a; y = b; } ShapeManager* ShapeManager::GetInstance() { static ShapeManager s_instance; return &s_instance; } ShapeManager::~ShapeManager() { auto it = m_shapes.begin(); auto end = m_shapes.end(); for (; it != end; ++it) { Shape* shape = (*it); shape->release(); } } void ShapeManager::addShape(Shape* shape) { shape->addRef(); m_shapes.push_back(shape); } float ShapeManager::getTotalArea() { float area = 0; auto it = m_shapes.begin(); auto end = m_shapes.end(); for (; it != end; ++it) { Shape* shape = (*it); area += shape->getArea(); } return area; } float Triangle::getArea() { return fabs(m_vertices[0].x * m_vertices[1].y + m_vertices[1].x * m_vertices[2].y + m_vertices[2].x * m_vertices[0].y - m_vertices[0].x * m_vertices[2].y - m_vertices[1].x * m_vertices[0].y - m_vertices[2].x * m_vertices[1].y) * 0.5; } }
最上面四行將idlcpp生成的四個代碼文件包含進來,其中Tutorial4.ic和Tutorial4.mc有具體實現代碼,不可在別的地方再次包含。後面是各個類型的成員函數的實現代碼。
LuaTutorial4.cpp代碼和之前的相似,只是去除了上面四個#include語句。
最後看一下腳本tutorial4.lua的內容:
triangle = paf.tutorial.Triangle(); triangle.m_vertices[0] = paf.tutorial.Point(0,0); triangle.m_vertices[1] = paf.tutorial.Point(0,1); triangle.m_vertices[2] = paf.tutorial.Point(1,1); shapeManager = paf.tutorial.ShapeManager.GetInstance(); shapeManager:addShape(triangle); print(shapeManager:getTotalArea()._);
編譯執行,結果以下圖: