关于虚函数,多重继承,Python中的super

继承和多重继承(http://en.wikipedia.org/wiki/Multiple_inheritance)是language features,是面向对象技术为了使程序向现实贴近的一个手段。不过在面向对象理论中多重继承也不是必须的,基本上所有可以用多重继承实现的,都可以通过单继承来work around。这句话更多来自于实践而不是严格的理论。

从继承的实现角度来说,当子类对象被初始化时,实际上有一个父类对象也被初始化并且组合到子类对象中。这种来自继承的组合和普通的组合的不同之处主要在于,我们是仅仅需要使用父类提供的功能,还是说也需要使用父类提供的接口。

有继承就有多态。C++为了实现多态引入了late/dynamic/runtime binding(Connecting a function call to a function body is called binding):编译时,编译器不知道通过一个基类引用调用的某函数,具体调用的到底是那段代码。所以传统的非OOP编译器的early/static binding机制就行不通了。C++中实现late binding的手段是虚函数。Python和Java中所有的函数/方法实际上都是虚的。所以说虚函数只是实现多态的一个(并不唯一的)技术手段。

具体的实现机制是,编译器为每一个包含虚函数的类(包括通过继承得来虚函数的类)都生成一段分配空间并初始化VTABLE(就是所谓的虚函数表)的代码。于是在运行的时候内存中就会有这样的VTABLE,它们包含了该类中所有虚函数的实现代码的地址。这是非常合乎逻辑的,因为同一个具体类的所有对象,其虚函数实现都是一样的,所以一个类只需要一个虚函数表。

接下来,每当编译器在源代码中看到new一个对象的时候,都会做一些小偷小摸的事:它会生成一些额外的代码,在对象中在分配空间给一个指针成员变量VPTR(对程序员是不可见的!!!),通常被放在对象内存布局最开始的地方,也就是this指针指向的地址。这个VPTR指向本对象的类所属的VTABLE。这部分代码被十分自然的放在构造器中,所以运行时new一个对象出来,对象被初始化后,这个VPTR就已经ready好了。明白了吧!这就是为什么如果程序员不写构造器,编译器会搞个默认构造器出来。Java中也是这样。

但是VTABLE的地址是在运行时才available的。初始化VPTR这段代码必须在运行时获得本对象的类型信息才能知道正确的VTABLE是哪个!所以编译器确实是插入了类型信息到对象中的。在运行时的时候可以获得。题外话:这也是RTTI的本质。

前面的说法有一个hole,就是如果一个对象多重继承怎么办?这样对于同一个对象就会有多个VTABLE。最直觉也是最家常的做法,就是搞多个VPTR出来,也是都放在对象头部。但这时就需要pointer fixups即thunks(http://en.wikipedia.org/wiki/Virtual_table),即当用不同的类型去引用该对象时,使用不同的VTABLE。

接下来的事情就简单了:当通过一个基类指针调用虚函数时,不管对象的具体类型是啥,总能找到正确的VTABLE,通过其找到被调用函数的正确地址,并调用之。

从语言使用者的角度来看,virtual只是一个关键字。使用者实际上不需要知道虚函数是怎么实现的。但由于虚函数调用会有额外的开销,有心的程序员会去研究它的实现并且在适当的时候才使用。

所谓纯虚函数,就是只有声明没有实现的函数。包含至少一个纯虚函数的类就是抽象类。

多重继承引入了二义性问题。最典型的菱形问题http://en.wikipedia.org/wiki/Diamond_problem。

C++使用虚函数来解决多态调用,使用了虚基类来解决菱形问题。

Python则规定了一个特别的method resolution order来摒除二义性:http://en.wikipedia.org/wiki/Diamond_problem。

Python中的super http://fuhm.net/super-harmful/ 

PyQt初览

为了攻读Qt我都被逼无奈去看万恶的C++的代码啦!我这麽一Python程序员。。。

当我看到这个语句,我本能的感觉到了问题,出离愤怒了。。。

emit dataChanged(index, index);

靠!搜了一下果然,是用preprocesser处理的:

http://doc.trolltech.com/3.3/signalsandslots.html

http://sigslot.sourceforge.net/

不消说,我讨厌这种繁复的东西。

其他值得注意的有,对于大多数的widgets来说,是不需要MVC这样的复杂设计的。table和tree特殊,就跟Java Swing中是一样的。model index可以看成是从model中取得数据的“坐标”,也跟Swing中差不多。

http://doc.trolltech.com/4.1/model-view-programming.html

MVC将视图和数据模型分开,一个好处就是一个数据模型可以对应多个不同的视图。

QString与Python string的转换是透明的。

CDT with Cygwin搞定debug环境

总感觉Eclipse CDT不是那么好用,尤其是Windows下。其实咱要求不高,不是非要达到Visual Studio的水平,毕竟这不是Eclipse的拳头产品。但是总不能太难使吧。。。

分页共1页 1