上一篇在這 C++混合編程之idlcpp教程Lua篇(6)
第一篇在這 C++混合編程之idlcpp教程(一)
與LuaTutorial4工程相似,工程LuaTutorial5中,同樣加入了四個文件:LuaTutorial5.cpp, Tutorial5.cpp, Tutorial5.i, tutorial5.lua。其中LuaTutorial5.cpp的內容基本和LuaTutorial4.cpp雷同,不再贅述。
首先看一下Tutorial5.i的內容:
#import "../../paf/src/pafcore/Reference.i"
$$#include <vector>
namespace tutorial
{
struct Point
{
float x;
float y;
Point();
Point(float a, float b);
meta:
Point(const Point ref pt);
};
export class Shape : Reference
{
export abstract float getArea();
$$ virtual ~Shape() {}
};
class ShapeManager(value_object)
{
void addShape(Shape ptr shape);
float getTotalArea();
static ShapeManager ptr GetInstance();
$*
~ShapeManager();
private:
std::vector<Shape*> m_shapes;
*$
};
class Triangle : Shape
{
Point m_vertices[$3];
meta:
Triangle();
$$virtual float getArea();
};
}
與Tutorial4.i相比,大部分內容是一樣的,不同之處在於類型Shape的聲明以及其下的純虛函數getArea;
export class Shape : Reference
export abstract float getArea();
在這兩處聲明的最前面都多了一個關鍵字export。這個關鍵字和C++中的export意義完全不一樣,只是想在C++中找一個現成的關鍵字直接使用而已,其實這個也不太合適,暫時先用著。此處的寫法意味著可以在腳本代碼中寫一個類型,讓它“派生”自Shape,並且能夠“覆蓋”虛函數getArea。當然實際上是通過idlcpp生成的一個派生類配合腳本插件代碼來完成類似的任務。
通過在類型的聲明class 前加上關鍵字export 表示此類型可以被腳本“派生”,在虛函數聲明的關鍵字virtual 或 abstract前加上關鍵字export 表示此虛函數可以被腳本“覆蓋”。
在宿主語言和腳本的混合使用中,一個常見的用法是在宿主語言中根據一定的條件向外發出事件,而用腳本語言來編寫事件處理代碼,例如在WOW中用一個XML文件描述GUI界面,同時注明事件處理函數對應的Lua函數名。idlcpp提供的腳本繼承C++類然後重寫虛函數的功能可以很好的實現類似的需求。
編譯後生成的Tutorial5.h的內容如下:
//DO NOT EDIT THIS FILE, it is generated by idlcpp
//http://www.idlcpp.org
#pragma once
#include "./Tutorial5.h"
#include "../../paf/src/pafcore/Reference.h"
namespace tutorial{ class ShapeManager; }
namespace tutorial{ class Triangle; }
#include <vector>
namespace tutorial
{
struct Point
{
public:
float x;
float y;
Point();
Point(float a,float b);
public:
static Point* New();
static Point* New(float a,float b);
static Point* NewArray(unsigned int count);
static Point* Clone(const Point& pt);
};
class Shape : public ::pafcore::Reference
{
public:
virtual ::pafcore::Type* getType();
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:
virtual ::pafcore::Type* getType();
Point m_vertices[3];
public:
static Triangle* New();
static Triangle* NewARC();
static Triangle* NewArray(unsigned int count);
static Triangle* NewArrayARC(unsigned int count);
virtual float getArea();
};
}
這裡生成的代碼和Tutorial4.h基本一致。
最後看一下Tutorial5.lua的內容
Circle = {}
Circle.__index = Circle;
function Circle.New()
circle= {radius = 1.0}
setmetatable(circle, Circle);
circle.shape = paf.tutorial.Shape._Derive_(circle);
return circle;
end
function Circle:getArea()
return self.radius * self.radius * 3.1415926;
end
circle = Circle.New();
circle.radius = 2.0;
shapeManager = paf.tutorial.ShapeManager.GetInstance();
shapeManager:addShape(circle.shape);
print(shapeManager:getTotalArea()._);
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:addShape(triangle);
print(shapeManager:getTotalArea()._);
在上面的代碼中,寫了一個類型Circle。在函數Circle.New 通過下面這一行
circle.shape = paf.tutorial.Shape._Derive_(circle);
來模擬繼承,語法:C++類型._Derive_(腳本對象) 用於完成模擬繼承的行為。實際上circle.shape才是C++類型Shape的派生類實例的引用,在C++中需要用到Shape類型的地方,將circle.shape傳遞過去即可,如下面的使用方式。
shapeManager:addShape(circle.shape);
然後在類型Circle中提供一個與C++基類同名的函數getArea用來計數圓的面積即可,最終使用時腳本插件會找到對應函數進行調用。
編譯執行,結果如下圖:
