用Boost.Python + CMake + wxPython構建跨語言GUI程序<三>
- Class Exposition
類是OO編程關于封裝的基本單元,圍繞其相關的主要是虛函數、成員變量、成員函數、構造、析構、繼承、多態的問題。
本示例新建于一個ExposeClass的子項目目錄,并且生成expose_class.so這個模塊庫。
前邊已經穿插了一些基本的使用方法,下邊是一些更復雜的東西。
1> 構造函數重載和數據成員、屬性
c++里邊運行聲明多個構造函數,并且一旦用戶聲明一個,編譯器不再生成默認構造函數;對于數據成員有簡單的public/private/protected三種訪問權限控制,以及很多人采用的getter/setter來模擬的屬性接口。對于構造函數重載,只需要多聲明幾個init函數即可,對于屬性和數據成員,可如下施為:
/////////////////////////////////////////////////////////////////////////////// struct World { //Constructors World(int i){ this->msg = "int parameter";} World(std::string msg) {this->msg = msg;} //Simple interface void set(std::string msg) { this->msg = msg; } std::string greet() { return msg; } std::string msg; //Data variable int name; int value; //Property std::string getProp() {return prop;} void setProp(const std::string& val) {prop = val;} private: std::string prop; };
上述的類可如下導出:
BOOST_PYTHON_MODULE(expose_class) { class_<World>("World", init<std::string>()) .def(init<int>()) .def("greet", &World::greet) .def("set", &World::set) .def_readonly("name", &World::name) .def_readwrite("value", &World::value) .add_property("roprop", &World::getProp) .add_property("prop", &World::getProp, &World::setProp) ;
上邊的init模板函數用于制定額外的構造函數。
read_only指定對應的name成員為只讀,read_write則說明對應的value是可讀寫的數據成員。
add_property則添加一個對應名字的Python熟悉,第一個參數為get方法的接口,第二個為set方法接口,如果只有一個被提供,那么對應的就是一個只讀屬性。
調用例子如下:
>>> import expose_class as cls >>> cls.World("str") <expose_class.World object at 0x7f3e29529e10> >>> cls.World(124) <expose_class.World object at 0x7f3e29529d60> >>> obj=_ >>> obj.name="name" Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: can't set attribute >>> obj.name 1 >>> obj.value="value" Traceback (most recent call last): File "<stdin>", line 1, in <module> Boost.Python.ArgumentError: Python argument types in None.None(World, str) did not match C++ signature: None(World {lvalue}, int) >>> obj.value=12 >>> obj.roprop="name" Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: can't set attribute >>> obj.roprop '' >>> obj.prop = "name" >>> obj.name 1 >>> obj.value 12 >>>
上邊例子中,企圖對read_only的變量或者屬性進行賦值的時候均發生異常而報錯。
2> 抽象類
所謂的抽象類意指其構造函數不能被外部調用,需要通過factory method來返回一個多態的指針,指向構造的子對象。
下邊是個簡單的抽象類的例子:
/////////////////////////////////////////////////////////////////////////////// //Abstract class struct Abstract { static std::string msg; void set(std::string msg) { this->msg = msg; } std::string greet() { return msg; } static Abstract* CreateInstance() { return new Abstract(); } }; std::string Abstract::msg = "default value";
導出的情況如下:
class_<Abstract>("Abstract", no_init) .def("greet", &Abstract::greet) .def("set", &Abstract::set) ;
def("CreateAbstract", Abstract::CreateInstance,
return_value_policy<manage_new_object>());
這里的no_init就是指定沒有構造函數可調用。
>>> import expose_class as test >>> test.Abstract() Traceback (most recent call last): File "<stdin>", line 1, in <module> RuntimeError: This class cannot be instantiated from Python >>> obj=test.CreateAbstract() >>> obj.greet() 'default value'
調用的時候,如果調用了這個Abstract的構造,就會拋出異常。對于factory method,由于返回的對象是函數內部構造于堆上的,因此用return_value_policy顯示的指明其生存期。
3> 繼承和虛函數
虛函數是c++實現多態機制和OO動態的核心所在,這里主要關注兩種情況,一種是純虛函數(強制之類提供自己的實現),一種是基類提供了默認實現的普通虛函數。
對于繼承而言,必須通過一個wrapper類來告知boost.python各個類之間的繼承關系。
純虛函數和一般虛函數的區別僅僅是沒有默認實現,在導出的時候,一般虛函數要多提供一個基類默認實現的函數,而純虛函數需要特別修飾聲明一下。
參考下邊這兩個類:
/////////////////////////////////////////////////////////////////////////////// //Inheritance struct Base { virtual ~Base() {}; //Virtual interface virtual int fun() = 0; virtual int func1(int i) { cout << "Default implementtion of func1" << endl; return 0; } }; struct Derived : Base { virtual int fun() { cout << "Derived implementation of fun!" << endl; return 0; } virtual int func1(int i) { cout << "Derived implementation of func1!" << endl; return 0; } };
接下來需要聲明一個wrapper類作為基礎來導出,告知基類信息。這里用了兩個函數,一個是純虛函數fun, 一個是普通虛函數func1.
對于純虛函數,只需要通過get_override得到具體的函數對象并調用即可(因為基類沒有實現);對于純虛函數,則要根據get_override的結果決定是否是基類,然后分別調用對應的函數。
具體的wrapper代碼如下: struct BaseWrap : Base, wrapper<Base> { //pure virtual implementation int fun() { return this->get_override("fun")(); } //pure virtual with default implementation int func1(int i) { if (override f = this->get_override("func1")) { return f(i); } else return Base::func1(i); } int default_func1(int i) {return Base::func1(i);} };
導出的代碼:
class_<BaseWrap, boost::noncopyable>("Base") .def("fun", pure_virtual(&Base::fun)) .def("fun1", &Base::func1, &BaseWrap::default_func1) ; class_<Derived, bases<Base> >("Derived");
這里在導出Derived的時候,直接用bases模板參數告知Boost.python它是Base的之類(不是BaseWrap的)。
4> Factory method
對于缺乏virtual contructor機制的c++來說,Factory method是一個很常用的生成之類對象的構造方法,如下(為簡單起見,只生成一個之類對象):
//Free functions on polymophism void baseFunc(Base* ptr) { ptr->fun(); ptr->func1(1); } void derivedFunc(Derived* ptr) { ptr->func1(2); } Base* factoryMethod() { return new Derived; }
這里也導出這個接口:
class_<Derived, bases<Base> >("Derived"); def("baseFunc", baseFunc); def("derivedFunc", derivedFunc); def("factoryMethod", factoryMethod, return_value_policy<manage_new_object>());
調用的例子:
>>> base_obj=test.Base() >>> dev_obj=test.Derived() >>> base_obj.fun() Traceback (most recent call last): File "<stdin>", line 1, in <module> RuntimeError: Pure virtual function called >>> dev_obj.fun() Derived implementation of fun! 0 >>> base_obj.fun1(1) Default implementtion of func1 0 >>> dev_obj.fun1(1) Derived implementation of func1! 0 >>> poly_obj=test.factoryMethod() >>> test.baseFunc(poly_obj) Derived implementation of fun! Derived implementation of func1!
posted on 2009-08-10 21:33 skyscribe 閱讀(1104) 評論(0) 編輯 收藏 引用