上一篇在這 C++混合編程之idlcpp教程Python篇(5)
第一篇在這 C++混合編程之idlcpp教程(一)
工程PythonTutorial4中加入了四個文件:PythonTutorial4.cpp, Tutorial4.cpp, Tutorial4.i, tutorial4.py。這個做法和以前不太一樣,前幾個工程中用.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);
meta:
Point(const Point ref pt);
};
class Shape : Reference
{
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();
};
}
首先是
#import "../../paf/src/pafcore/Reference.i"
#import相當於C++中的 #include 編譯時先將其所描述的文件中的內容插入到對應的位置。
第二行
$$#include <vector>
將#include <vector> 插入到Tutorial4.h的對應位置上。
在這裡仍然有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 ptr
typeName *
傳地址
typeName ref
typeName &
傳引用
typeName ptr ptr
typeName **
傳指針的地址
typeName new ptr
typeName **
傳指針的地址,用於接收函數內部new的對象,或者增加引用計數,外界需要delete或release
typeName new [] ptr
typeName **
傳指針的地址,用於接收函數內部new []的對象數組,外界需要delete []
typeName ptr ref
typeName *&
傳指針的引用
typeName new ref
typeName *&
傳指針的引用,用於接收函數內部new的對象,或者增加引用計數,外界需要delete或release
typeName new [] ref
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 "./Tutorial4.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();
};
}
在類型 Shape 和Triangle中,idlcpp為其添加了虛函數
virtual ::pafcore::Type* getType();
實現代碼見Tutorial4.ic。
此外class Triangle 中除了
static Triangle* New();
static Triangle* NewArray(unsigned int count);
這兩個由構造函數生成的靜態函數外,還多了
static Triangle* NewARC();
static Triangle* NewArrayARC(unsigned int count);
其間的區別見具體實現代碼,實現代碼在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
{
inline Point* Point::New()
{
return new Point();
}
inline Point* Point::New(float a,float b)
{
return new Point(a, b);
}
inline Point* Point::NewArray(unsigned int count)
{
return new_array<Point>(count);
}
inline Point* Point::Clone(const Point& pt)
{
return new Point(pt);
}
::pafcore::Type* Shape::getType()
{
return ::RuntimeTypeOf<Shape>::RuntimeType::GetSingleton();
}
::pafcore::Type* Triangle::getType()
{
return ::RuntimeTypeOf<Triangle>::RuntimeType::GetSingleton();
}
inline Triangle* Triangle::New()
{
return new ::pafcore::RefCountObject<Triangle>();
}
inline Triangle* Triangle::NewARC()
{
return new ::pafcore::AtomicRefCountObject<Triangle>();
}
inline Triangle* Triangle::NewArray(unsigned int count)
{
return new_array<::pafcore::RefCountObject<Triangle>>(count);
}
inline Triangle* Triangle::NewArrayARC(unsigned int count)
{
return new_array<::pafcore::AtomicRefCountObject<Triangle>>(count);
}
}
注意一下下面兩個函數的區別
static Triangle* New();
static Triangle* NewARC();
在::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有具體實現代碼,不可在別的地方再次包含。後面是各個類型的成員函數的實現代碼。
PythonTutorial4.cpp代碼和以前的類似,只是去除了上面四個#include語句。
最後看一下腳本tutorial4.py的內容:
import pafpython; paf = pafpython.paf; 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()._);
編譯執行,結果如下圖:
