VCL中的虚拟构造函数有什么意义?

ooolinux 2019-10-09 10:11:05
老概以前说过:

构造顺序和一般对象的构造是一样的,只不过它构造函数的地址不是编译时确定,而是运行时确定。构造函数可以virtual对于VCL这种类库的设计至关重要,它允许创建程序编译时未知的类实例,只要该类的基类已知就可以。VCL中凡是支持设计时的组件都必须继承自TComponent或者它的派生类,而TComponent的构造函数就是virtual的。
https://bbs.csdn.net/topics/392069877

————————
当时不太理解,后来知道Delphi有一个类类型,TClass。
不过这句不太理解:
它允许创建程序编译时未知的类实例
VCL中什么类型是编译时未知的呢?如果窗体上放一个按钮,类型不就是TButton吗?
...全文
157 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
引用 8 楼 ooolinux 的回复:
但是创建对象实例的时候,不需要针对每一种类型单独创建(也不可能),能够以统一的方式建立
————
是不是这样理解,如果针对每一种类型单独创建,就需要:
class TButton;
class TPanel;
class TListBox;
等等把所有类全部前置声明一遍?


问题在于,IDE本身被编译的时候,并不知道有没有某些类,比如N多的第三方组件,当时这些类甚至还没有被写出来,所以它不可能以xxx.Create;或者new xxx;这种方式创建设计时组件实例。
ooolinux 2019-10-12
  • 打赏
  • 举报
回复
引用 11 楼 早打大打打核战争 的回复:
[quote=引用 8 楼 ooolinux 的回复:]
但是创建对象实例的时候,不需要针对每一种类型单独创建(也不可能),能够以统一的方式建立
————
是不是这样理解,如果针对每一种类型单独创建,就需要:
class TButton;
class TPanel;
class TListBox;
等等把所有类全部前置声明一遍?


问题在于,IDE本身被编译的时候,并不知道有没有某些类,比如N多的第三方组件,当时这些类甚至还没有被写出来,所以它不可能以xxx.Create;或者new xxx;这种方式创建设计时组件实例。
[/quote]

明白了
ooolinux 2019-10-11
  • 打赏
  • 举报
回复
引用 9 楼 BlueStorm 的回复:
Delphi的RTTI&VMT
好的
BlueStorm 2019-10-11
  • 打赏
  • 举报
回复
ooolinux 2019-10-11
  • 打赏
  • 举报
回复
引用 7 楼 早打大打打核战争 的回复:
IDE通过RTTI,是可以从设计时包里面获取组件的类型的,还有属性类型和事件原型,但是创建对象实例的时候,不需要针对每一种类型单独创建(也不可能),能够以统一的方式建立,比如: function CreateObject(AClass: TClass): TObject; begin Result := AClass.Create; end; 之后就可以: var a, b, c: TObject; begin a := CreateObject(TComponent); b := CreateObject(TPanel); c := CreateObject(TBitmap); writeln('a is a ', a.ClassName); writeln('b is a ', b.ClassName); writeln('c is a ', c.ClassName); end;
但是创建对象实例的时候,不需要针对每一种类型单独创建(也不可能),能够以统一的方式建立 ———— 是不是这样理解,如果针对每一种类型单独创建,就需要: class TButton; class TPanel; class TListBox; 等等把所有类全部前置声明一遍?
  • 打赏
  • 举报
回复
IDE通过RTTI,是可以从设计时包里面获取组件的类型的,还有属性类型和事件原型,但是创建对象实例的时候,不需要针对每一种类型单独创建(也不可能),能够以统一的方式建立,比如:
function CreateObject(AClass: TClass): TObject;
begin
Result := AClass.Create;
end;
之后就可以:
var
a, b, c: TObject;
begin
a := CreateObject(TComponent);
b := CreateObject(TPanel);
c := CreateObject(TBitmap);
writeln('a is a ', a.ClassName);
writeln('b is a ', b.ClassName);
writeln('c is a ', c.ClassName);
end;
ooolinux 2019-10-10
  • 打赏
  • 举报
回复
引用 5 楼 武稀松 的回复:
[quote=引用 4 楼 ooolinux 的回复:] [quote=引用 3 楼 早打大打打核战争 的回复:] IDE自身编译的时候并不知道TImageEn是什么,甚至那时TImageEn还不存在,TImageEn的相关信息是IDE在运行时通过RTTI获得的 简单说,非virtual构造函数的地址是编译时确定的,因此无法创建在程序自身编译时还不存在/未知的类的实例,典型如存在于另一个二进制模块(比如包)中的类
把一个ImageEn控件放在窗体上,然后编译项目,编译器不知道ImageEn控件的类型吗? [/quote] 实际上IDE面对的只是TComponent或者TControl这两种类型的派生类。 那么拖拽一个控件到设计器上,设计器创建这个实例的时候都是当做TComponent创建的,他可不知道是不是TImageEN。但是因为构造函数是虚的,而且有比CPP更加厉害的RTTI信息,一个类知道自己是什么,是谁派生出来的,于是能正确的创建自己。 可以理解为所有能在设计期间可见的组件都是TComponentClass的一种,也就是class of TComponent. 对于IDE来说不关你是什么,我都按照TComponentClass调用构造函数就行了 [/quote] 不是特别理解,为什么: 拖拽一个控件到设计器上,设计器创建这个实例的时候都是当做TComponent创建的,他可不知道是不是TImageEN
武稀松 2019-10-10
  • 打赏
  • 举报
回复
引用 4 楼 ooolinux 的回复:
[quote=引用 3 楼 早打大打打核战争 的回复:]
IDE自身编译的时候并不知道TImageEn是什么,甚至那时TImageEn还不存在,TImageEn的相关信息是IDE在运行时通过RTTI获得的
简单说,非virtual构造函数的地址是编译时确定的,因此无法创建在程序自身编译时还不存在/未知的类的实例,典型如存在于另一个二进制模块(比如包)中的类


把一个ImageEn控件放在窗体上,然后编译项目,编译器不知道ImageEn控件的类型吗?
[/quote]
实际上IDE面对的只是TComponent或者TControl这两种类型的派生类。
那么拖拽一个控件到设计器上,设计器创建这个实例的时候都是当做TComponent创建的,他可不知道是不是TImageEN。但是因为构造函数是虚的,而且有比CPP更加厉害的RTTI信息,一个类知道自己是什么,是谁派生出来的,于是能正确的创建自己。

可以理解为所有能在设计期间可见的组件都是TComponentClass的一种,也就是class of TComponent.
对于IDE来说不关你是什么,我都按照TComponentClass调用构造函数就行了

ooolinux 2019-10-10
  • 打赏
  • 举报
回复
引用 3 楼 早打大打打核战争 的回复:
IDE自身编译的时候并不知道TImageEn是什么,甚至那时TImageEn还不存在,TImageEn的相关信息是IDE在运行时通过RTTI获得的
简单说,非virtual构造函数的地址是编译时确定的,因此无法创建在程序自身编译时还不存在/未知的类的实例,典型如存在于另一个二进制模块(比如包)中的类


把一个ImageEn控件放在窗体上,然后编译项目,编译器不知道ImageEn控件的类型吗?
  • 打赏
  • 举报
回复
IDE自身编译的时候并不知道TImageEn是什么,甚至那时TImageEn还不存在,TImageEn的相关信息是IDE在运行时通过RTTI获得的
简单说,非virtual构造函数的地址是编译时确定的,因此无法创建在程序自身编译时还不存在/未知的类的实例,典型如存在于另一个二进制模块(比如包)中的类

ooolinux 2019-10-10
  • 打赏
  • 举报
回复
引用 1 楼 早打大打打核战争 的回复:
比如在IDE中安装了第三方组件,IDE可以在设计时实例化某些组件,这些组件的类就是在IDE自身编译时未知的


第三方组件放上去的时候,IDE也知道它的类型亚,比如TImageEn。
  • 打赏
  • 举报
回复
比如在IDE中安装了第三方组件,IDE可以在设计时实例化某些组件,这些组件的类就是在IDE自身编译时未知的

828

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 非技术区
社区管理员
  • 非技术区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧