版权所有:nicrosoft
文章来源:东日制作室
在《浅谈多态——概念描述》一文中,提到多态的本质就是“将子类类型的指针赋值给父类类型的指针”。那么,为什麽这种赋值是允许的,或者说是安全的呢?反过来行不行?虚函数的动态绑定是如何实现的呢?这些问题都将在本文得到解答。
假设有如下代码(object pascal语言描述):
t1 = class
private
member1 : integer;
public
function func1 : integer; virtual;
function func2 : integer; virtual;
function func3 : integer; virtual;
end;
t2 = class(t1)
private
member2 : integer;
public
function func1 : integer; override;
function func2 : integer; override;
end;
最终结果是,t1类的实例的内存分布图如下(仅说明原理,并不表示编译器一定也是如此实现):
其中,vptr是编译器自动加入的一个成员指针(称为虚指针)。只有存在虚函数或动态函数或纯虚函数的类才会被编译器加入这个成员指针,该指针指向一个称为“虚函数表”(object pascal中成为“虚方法表”——vmt)的内存区域。虚函数表中,保存了每一个虚函数的入口地址。
t2类的实例的内存分布图如下:
从图中我们可以知道,子类对象所占的空间大于父类对象所占空间。因此,当发生将子类类型的指针赋值给父类类型的指针的赋值时(即所谓的“向上映射”),也就是父类类型的指针指向了子类类型的对象所占的内存空间,那么,很显然,可以保证父类类型指针的可访问范围都是有效,所以这种“向上映射”是绝对安全的(所谓“向上”是指类层次的上下关系,父类在上,子类在下)。这种赋值是得到编译器认可的。
也可以很容易得出结论,“向下映射”则未必安全(除非程序员真正知道指针所指对象的实际类型)。因此,这种赋值是不被编译器允许的,当然,程序员可以通过类似 t1(obj) 的形式进行强制类型转换,但这种强制类型转换很不安全(可以发生在任何类和类之间),object pascal推荐使用 as 算符进行类型之间的转换,如: (obj as t1),使用 as 算符,编译器会检查对象类型和目标类型是否相容。
如果相容,转换被允许,否则编译出错。
Java Asp PHP .Net XML C/C++ CGI VB Jsp J2ee J2se J2me EJB Servlet Tomcat Resin Struts Weblogic Eclipse ANT GUI JMS Web servise IDEA Webphere Hibernate Spring Jboss Applet Swing Socket Javamail Perl Ajax P2P 安全 模式 框架 测试 开源 游戏
Windows XP Windows 2000 Windows 2003 Windows Me Windows 9.x Linux UNIX 注册表 操作系统 服务器 应用服务器