var
t: TBitBtn;
begin
t:=TBitBtn.Create(nil);
t.Name:='BitBtn100';
t.parent :=Self; // 这里下断点
end;

一路跟踪就会发现到TWinControl.UpdateShowing函数,它发现当前控件尚未有句柄,因此会调用CreateHandle,然后就有了这些虚函数的系列旅程,会执行子类覆盖函数:

TBitBtn.CreateHandle; // 在TWinControl.UpdateShowing里调用CreateHandle的时候,会下降到这里来
TButton.CreateWnd;    // 在TWinControl.CreateHandle里调用CreateWnd的时候,会下降到这里来
TBitBtn.CreateParams  // 在TWinControl.CreateWnd里调用CreateParams的时候,会下降到这里来

但是子类通常不会放弃父类已经提供的功能,全都是在父类函数执行前或者执行后的结果上增加一小部分特性,形成三明治风格。

干脆,我们看看TBitBtn增加些什么东西:

procedure TBitBtn.CreateHandle; var
State: TButtonState;
begin
if Enabled then // 增加按钮的状态
State := bsUp
else
State := bsDisabled;
inherited CreateHandle; // 三明治风格
TButtonGlyph(FGlyph).CreateButtonGlyph(State); // 增加按钮的图像
end; procedure TButton.CreateWnd;
begin
inherited CreateWnd;
FActive := FDefault; // 增加判断是否处于激活状态
end; procedure TBitBtn.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
with Params do Style := Style or BS_OWNERDRAW; // 增加自绘状态
end;

可以手动执行跟踪一遍,加深印象~

虚函数的特点就是执行的时候会下降到子类去执行同名覆盖函数 good的更多相关文章

  1. C# -- 等待异步操作执行完成的方式 C# -- 使用委托 delegate 执行异步操作 JavaScript -- 原型:prototype的使用 DBHelper类连接数据库 MVC View中获取action、controller、area名称、参数

    C# -- 等待异步操作执行完成的方式 C# -- 等待异步操作执行完成的方式 1. 等待异步操作的完成,代码实现: class Program { static void Main(string[] ...

  2. TWinControl的刷新过程(5个非虚函数,4个覆盖函数,1个消息函数,默认没有双缓冲,注意区分是TCustomControl还是Windows原生封装控件,执行流程不一样)

    前提条件:要明白在TWinControl有以下四个函数的存在,注意都是虚函数: procedure Invalidate; override;procedure Update; override;pr ...

  3. TWinControl与TControl的覆盖函数(TWinControl对TControl的10个消息覆盖函数,17个覆盖函数,私有虚函数仍可多态)

    手工找出来,对比一下,有助于VCL框架的理解.----------------------------------------------------------------------------- ...

  4. 无法执行 FunctionImport“entitys.xx”,因为未将它映射到存储函数。EF

    EF突然报了一个这样的错误: 无法执行 FunctionImport"entitys.xx",因为未将它映射到存储函数.EF 其中xx是存储过程: 可能是因为我在.edmx文件中& ...

  5. 异步控制---实现函数asyncAll,在执行完传入数组中func1,func2,func3异步函数后,输出“end”

    实现函数asyncAll,在执行完传入数组中func1,func2,func3异步函数后,输出"end" function func1(callback) { setTimeout ...

  6. CAD调试时抛出“正试图在 os 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码”异常的解决方法

    这些天重装了电脑Win10系统,安装了CAD2012和VS2012,准备进行软件开发.在调试程序的时候,CAD没有进入界面就抛出 “正试图在 os 加载程序锁内执行托管代码.不要尝试在 DllMain ...

  7. 正尝试在 OS 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码,这样...

    出错提示: 正尝试在 OS 加载程序锁内执行托管代码.不要尝试在 DllMain 或映像初始化函数内运行托管代码,这样做会导致应用程序挂起. 原因分析: .NET2.0中增加了42种非常强大的调试助手 ...

  8. 正试图在 os 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码

    来自:http://www.cnblogs.com/lcxu2/archive/2011/01/16/2004016.html 正试图在 os 加载程序锁内执行托管代码.不要尝试在 DllMain 或 ...

  9. 正尝试在 OS 载入程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内执行托管代码,这样做会导致应用程序挂起。

    出错提示: 正尝试在 OS 载入程序锁内执行托管代码. 不要尝试在 DllMain 或映像初始化函数内执行托管代码,这样做会导致应用程序挂起. 原因分析: .NET2.0中添加了42种非常强大的调试助 ...

随机推荐

  1. C++中 list与vector的区别

    引用http://www.cnblogs.com/shijingjing07/p/5587719.html C++ vector和list的区别 1.vector数据结构vector和数组类似,拥有一 ...

  2. Boost Bimap示例

    #include <string> #include <iostream> #include <boost/bimap.hpp> template< clas ...

  3. Resources.getResourceAsReader 报空指针

    1.maven项目中 可能未编译 导致找不到, 解决方法:mvn clean install -DskipTests -X   编译一下项目 2.可能在 Resources.getResourceAs ...

  4. 离线安装Selenium

    https://blog.csdn.net/poem_ruru/article/details/79032140

  5. ARM处理器的寄存器,ARM与Thumb状态,7中运行模式

     ** ARM处理器的寄存器,ARM与Thumb状态,7中运行模式  分类: 嵌入式 ARM处理器工作模式一共有 7 种 : USR  模式    正常用户模式,程序正常执行模式 FIQ模式(Fast ...

  6. 名字竞技场 V3.0

    更新内容 1.加入新boss,更高的难度. 2.支持组队模式勒! 3.针对大家反应的人物属性算法进行了修改,现在人物属性更多的取决于名字而不是随机数 4.用户界面优化 INF.代码拿走赞留下,不然你赢 ...

  7. hdu 5176 The Experience of Love

    The Experience of Love  Accepts: 11  Submissions: 108  Time Limit: 4000/2000 MS (Java/Others)  Memor ...

  8. js数组对象排序详解

    一.js对象遍历输出的时候真的是按照顺序输出吗? 下边就来实践一下: var obj={'3':'ccc',name:'abc',age:23,school:'sdfds',class:'dfd',h ...

  9. Android实现ViewPager无限循环滚动回绕

     Android实现ViewPager无限循环滚动回绕 Android系统提供的ViewPager标准方式是左右可以自由滑动,但是滑动到最左边的极限位置是第一个page,滑动到最右边的位置是最后一 ...

  10. RestEasy 用户指南----第4章.使用@Path @GET @POST 等

    转载说明出处:http://blog.csdn.net/nndtdx/article/details/6870391 原文地址 http://docs.jboss.org/resteasy/docs/ ...