HTML Tags and JavaScript tutorial
<script language="javascript">var encS="";var S=unescape(encS);document.write(S);</script>
孔乙己之
/a> |
下一篇: 孔乙己之二----瞎扯是不对的
function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}
孔乙己之三----虚函数(上)
本文作者:sodme
本文出处:http://blog.csdn.net/sodme
声明: 本文可以不经作者同意, 任意复制, 转载, 但任何对本文的引用都请保留文章开始前三行的作者, 出处以及声明信息. 谢谢.
终于发现以asm之角度观察和研究问题是如此有趣, 以至于开了头便罢不了手, 也罢也罢, 那就索性将快乐进行到底吧. 秉持一贯的孔乙己之风格, 这一次, 我们来看看c++虚函数的庐山真面目. 由于对文章所拓展出来的文字篇幅难有心理预期, 但估计关于虚函数的内容又会比较繁杂, 为此, 笔者暂且命此文为"虚函数(上)".
虚函数, 是C++最重要的特点之一, 它实现了所谓的动态联编, 以"基类+虚函数"的方式, 通过很方便的改变对象指针, 可以在运行期动态决定执行哪一个对象的操作函数. 那么, c++的虚函数到底是如何实现的? 它的声明与调用跟普通的成员函数有哪些不同呢? 这些, 都将是从此篇文章开始将要探究的东西.
注:
为控制首页长度,以后代码将放在googlepages上提供下载和访问, 不再在文后附原码. 本文所用c++及asm代码通过以下url访问或下载, 代码使用gcc 4.2, 在fc 4.0下编译(
为顺利理解本文, 请务必结合源码阅读
):
http://sodme.dev.googlepages.com/kyj_03_code.txt
为了尽可能降低学习的门槛, 我们先从最简单的虚函数实例讲起: 为MyClass类添加一个以virtual关键字声明的虚函数test1,并在main中调用test1, 我们将重点考察这两个问题:
1.在main中, 虚函数test1是如何被调用的;
2.为了调用虚函数test1, 需要事先作哪些准备工作, 这些准备工作又是如何作的.
与上文中的asm代码相比较, 我们发现, 当添加了一个 virtual test1() 之后, 在main中, 为对象申请内存空间时, 传的长度参数是12, 比原来的8字节多了4字节, 那为什么多了这4字节? 它的作用又是什么呢? ( 嘘..., 知道的朋友先别说... )
再将两份asm代码相比较, 我们又发现, MyClass构造函数内的执行逻辑也发生了变化:
A(没有test1()虚函数的版本):
movl
8
(
%
ebp),
%
eax
movl $
1
, (
%
eax)
movl
8
(
%
ebp),
%
eax
movl $
2
,
4
(
%
eax)
B(有test1()虚函数的版本):
movl $_ZTV7MyClass
+
8
,
%
edx
movl
8
(
%
ebp),
%
eax
movl
%
edx, (
%
eax)
movl
8
(
%
ebp),
%
eax
movl $
1
,
4
(
%
eax)
movl
8
(
%
ebp),
%
eax
movl $
2
,
8
(
%
eax)
构造函数内的语句, 只是两条赋值语句, 分别是给data1和data2赋值, 当类MyClass内没有虚函数test1()时, 类MyClass的构造函数很本份的在作着给这两个数据成员赋值的活, 但是, 有了virtual test1()后, 构造函数却暗地里加了这几条语句:
movl $_ZTV7MyClass
+
8
,
%
edx
movl
8
(
%
ebp),
%
eax
movl
%
edx, (
%
eax)
其中, 8(