類(lèi)是OO編程關(guān)于封裝的基本單元,圍繞其相關(guān)的主要是虛函數(shù)、成員變量、成員函數(shù)、構(gòu)造、析構(gòu)、繼承、多態(tài)的問(wèn)題。
本示例新建于一個(gè)ExposeClass的子項(xiàng)目目錄,并且生成expose_class.so這個(gè)模塊庫(kù)。
前邊已經(jīng)穿插了一些基本的使用方法,下邊是一些更復(fù)雜的東西。
1> 構(gòu)造函數(shù)重載和數(shù)據(jù)成員、屬性
c++里邊運(yùn)行聲明多個(gè)構(gòu)造函數(shù),并且一旦用戶聲明一個(gè),編譯器不再生成默認(rèn)構(gòu)造函數(shù);對(duì)于數(shù)據(jù)成員有簡(jiǎn)單的public/private/protected三種訪問(wèn)權(quán)限控制,以及很多人采用的getter/setter來(lái)模擬的屬性接口。對(duì)于構(gòu)造函數(shù)重載,只需要多聲明幾個(gè)init函數(shù)即可,對(duì)于屬性和數(shù)據(jù)成員,可如下施為:
///////////////////////////////////////////////////////////////////////////////
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;
};
上述的類(lèi)可如下導(dǎo)出:
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模板函數(shù)用于制定額外的構(gòu)造函數(shù)。
read_only指定對(duì)應(yīng)的name成員為只讀,read_write則說(shuō)明對(duì)應(yīng)的value是可讀寫(xiě)的數(shù)據(jù)成員。
add_property則添加一個(gè)對(duì)應(yīng)名字的Python熟悉,第一個(gè)參數(shù)為get方法的接口,第二個(gè)為set方法接口,如果只有一個(gè)被提供,那么對(duì)應(yīng)的就是一個(gè)只讀屬性。
調(diào)用例子如下:
>>> 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
>>>
上邊例子中,企圖對(duì)read_only的變量或者屬性進(jìn)行賦值的時(shí)候均發(fā)生異常而報(bào)錯(cuò)。
2> 抽象類(lèi)
所謂的抽象類(lèi)意指其構(gòu)造函數(shù)不能被外部調(diào)用,需要通過(guò)factory method來(lái)返回一個(gè)多態(tài)的指針,指向構(gòu)造的子對(duì)象。
下邊是個(gè)簡(jiǎn)單的抽象類(lèi)的例子:
///////////////////////////////////////////////////////////////////////////////
//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";
導(dǎo)出的情況如下:
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就是指定沒(méi)有構(gòu)造函數(shù)可調(diào)用。
>>> 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'
調(diào)用的時(shí)候,如果調(diào)用了這個(gè)Abstract的構(gòu)造,就會(huì)拋出異常。對(duì)于factory method,由于返回的對(duì)象是函數(shù)內(nèi)部構(gòu)造于堆上的,因此用return_value_policy顯示的指明其生存期。
3> 繼承和虛函數(shù)
虛函數(shù)是c++實(shí)現(xiàn)多態(tài)機(jī)制和OO動(dòng)態(tài)的核心所在,這里主要關(guān)注兩種情況,一種是純虛函數(shù)(強(qiáng)制之類(lèi)提供自己的實(shí)現(xiàn)),一種是基類(lèi)提供了默認(rèn)實(shí)現(xiàn)的普通虛函數(shù)。
對(duì)于繼承而言,必須通過(guò)一個(gè)wrapper類(lèi)來(lái)告知boost.python各個(gè)類(lèi)之間的繼承關(guān)系。
純虛函數(shù)和一般虛函數(shù)的區(qū)別僅僅是沒(méi)有默認(rèn)實(shí)現(xiàn),在導(dǎo)出的時(shí)候,一般虛函數(shù)要多提供一個(gè)基類(lèi)默認(rèn)實(shí)現(xiàn)的函數(shù),而純虛函數(shù)需要特別修飾聲明一下。
參考下邊這兩個(gè)類(lèi):
///////////////////////////////////////////////////////////////////////////////
//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;
}
};
接下來(lái)需要聲明一個(gè)wrapper類(lèi)作為基礎(chǔ)來(lái)導(dǎo)出,告知基類(lèi)信息。這里用了兩個(gè)函數(shù),一個(gè)是純虛函數(shù)fun, 一個(gè)是普通虛函數(shù)func1.
對(duì)于純虛函數(shù),只需要通過(guò)get_override得到具體的函數(shù)對(duì)象并調(diào)用即可(因?yàn)榛?lèi)沒(méi)有實(shí)現(xiàn));
對(duì)于純虛函數(shù),則要根據(jù)get_override的結(jié)果決定是否是基類(lèi),然后分別調(diào)用對(duì)應(yīng)的函數(shù)。
具體的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);}
};
導(dǎo)出的代碼:
class_<BaseWrap, boost::noncopyable>("Base")
.def("fun", pure_virtual(&Base::fun))
.def("fun1", &Base::func1, &BaseWrap::default_func1)
;
class_<Derived, bases<Base> >("Derived");
這里在導(dǎo)出Derived的時(shí)候,直接用bases模板參數(shù)告知Boost.python它是Base的之類(lèi)(不是BaseWrap的)。
4> Factory method
對(duì)于缺乏virtual contructor機(jī)制的c++來(lái)說(shuō),F(xiàn)actory method是一個(gè)很常用的生成之類(lèi)對(duì)象的構(gòu)造方法,如下(為簡(jiǎn)單起見(jiàn),只生成一個(gè)之類(lèi)對(duì)象):
//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; }
這里也導(dǎo)出這個(gè)接口:
class_<Derived, bases<Base> >("Derived");
def("baseFunc", baseFunc);
def("derivedFunc", derivedFunc);
def("factoryMethod", factoryMethod,
return_value_policy<manage_new_object>());
調(diào)用的例子:
>>> 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!