上一篇在這 C++混合編程之idlcpp教程Lua篇(4)
第一篇在這 C++混合編程之idlcpp教程(一)
與前面的工程相似,工程LuaTutorial3中,同樣加入了三個文件:LuaTutorial3.cpp, Tutorial3.i, tutorial3.lua 。其中LuaTutorial3.cpp的內容基本和LuaTutorial2.cpp雷同,不再贅述。
首先看一下Tutorial3.i的內容:
namespace tutorial { struct Point { float x; float y; nocode Point(); nocode Point(float a, float b); nocode Point(const Point& pt); #{ Point() {} Point(float a, float b) { x = a; y = b; } #} }; struct Shape { abstract float getArea(); ## virtual ~Shape() {} }; struct Triangle : Shape { Point m_vertices[#3]; nocode static Triangle+ New(); #{ virtual float 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; } static Triangle* New() { return new Triangle; } #} }; }
在這里仍然有struct Point。 引入了基類 struct Shape。其中這一行
abstract float getArea();
表示聲明一個純虛函數,相當于C++中的
virtual float getArea() = 0;
如果不是純虛函數,使用關鍵字virtual代替abstract即可。
新加入了類型 Triangle
struct Triangle : Shape
與C++一樣,用 : 表示繼承。因idlcpp表示的是接口信息,所以只有公有繼承。與C++不同,idlcpp并沒有public, protected, private這三個關鍵字。
然后是數據成員m_vertices;
Point m_vertices[#3];
idlcpp只關心接口的信息,在其語法分析部分,只能看見Point m_vertices[]。數字3需要用插入代碼的方式。其中#表示直接連在后面的一個標識符或整數(實際上是由字母,下劃線和數字組成的串)將插入到生成的C++頭文件對應的位置上。下一行
nocode static Triangle+ New();
聲明了一個名為New的靜態函數,其實現代碼就在后續的類型聲明內,所以此處用nocode阻止在頭文件中生成函數聲明,如前所述,idlcpp如果看見了構造函數的聲明,會生成靜態函數New,所以此時不能出現構造函數的聲明,以免名字沖突。對照一下后面實現部分的C++聲明
static Triangle* New()
這里和C++不一致的地方是用+代替了*,放在函數返回值類型與函數名之間,表示函數內部以new的形式創建了一個對象,返回其指針,外界需要用delete的形式刪除它(還有另一種關于引用計數的情況,暫不討論)。在腳本語言中一般自帶垃圾收集機制,腳本語言自動管理內存的分配釋放。程序員一般不用關心何時刪除對象這樣的問題,而在C++中在堆上分配對象的生命期一般由程序員維護。為處理其間的差異,idlcpp在函數聲明的返回值類型部分有如下幾種形式:
|
idlcpp聲明 |
C++聲明 |
實現 |
|
typeName |
typeName |
返回值 |
|
typeName & |
typeName& |
返回引用 |
|
typeName * |
typeName* |
返回指針 |
|
typeName + |
typeName* |
返回指針,外界需要delete,或者增加了引用計數,外界需要release |
|
typeName + [] |
typeName* |
返回指針,外界需要delete[] |
例如下面的C++代碼:
int g_a; int* getGlobal() { return &g_a; } int* getNew() { return new int; } int* getNewArray(int count) { return new int[count]; }
三個函數的返回值類型都是int*,但對于后面兩個,分別要用delete 和delete[]釋放內存,就語法層面看,從函數的聲明不能區分這些情況。只能由程序員根據實際情況進行不同的處理。而在腳本語言中并不希望看到顯示的刪除對象的調用。所以idlcpp通過語法層面的聲明,在生成的元數據代碼中進行區分,然后由運行時庫(pafcore.dll)進行處理。
編譯后生成的Tutorial3.h的內容如下:
//DO NOT EDIT THIS FILE, it is generated by idlcpp //http://www.idlcpp.org #pragma once #include "./Tutorial3.h" namespace tutorial{ struct Triangle; } namespace tutorial { struct Point { public: float x; float y; Point() {} Point(float a, float b) { x = a; y = b; } }; struct Shape { public: virtual float getArea() = 0 ; virtual ~Shape() {} }; struct Triangle : public Shape { public: Point m_vertices[3]; virtual float 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; } static Triangle* New() { return new Triangle; } }; }
內容基本上都是和Tutorial3.i中一一對應的。然后看一下腳本tutorial3.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); print(triangle:getArea()._);
創建了一個tirangle對象,然后設置數據成員,此處運行時能夠檢測下標的范圍為0至2,如果超出范圍將會報錯,最后調用其基類Shape中聲明的函數getArea(),因為這是虛函數,所以最終會調用到Traingle::getArea()。
編譯運行結果如下圖:

浙公網安備 33010602011771號