主页C++ Builder 资料C++ Builder 参考手册基础知识PME 架构/PME 模型
C++ Builder 串口控件
C++ Builder 编程技巧
C++ Builder 操作指南
C++ Builder 参考手册
基础知识
 • PME 架构/PME 模型
 • 判断编译器版本
 • 数据对齐方式
cfloat 浮点数
cmath 数学函数
cstdlib 标准库函数
System 字符串
System 日期和时间
System.Math.hpp 数学函数
其他数据类型
VCL 基础类
VCL 应用程序
Pictures 图片
Graphics 绘图
Additional 控件
System 控件
A ~ Z 字母顺序排列的目录
网友留言/技术支持
PME 架构/PME 模型 - PME = Property-Method-Event, 即:属性-方法-事件
P: 属性,__property 关键字
M: 方法,类的成员函数
E: 事件,__closure 关键字

P: 属性,__property 关键字

从使用者的角度来看,属性就像是类的成员变量,可以给这个变量赋值,也可以读出变量的值,
但是属性的内部,可以对应读写的处理函数,对属性赋值,会调用写入属性的函数,读出属性值,会调用读取属性的函数。

__property type PropertyName = { attributes };
__property type PropertyName[type1] = { attributes };
__property type PropertyName[type1][type2] = { attributes };

__property PropertyName;
__property PropertyName = { attributes };

项目 描述
type 变量类型。从使用者的角度看,属性就像是类的成员变量,这是这个变量的变量类型。
如果不写类型,那么这个属性必须是类继承过来的,这个属性和父类的同名属性的类型相同。
PropertyName 属性名称。从使用者的角度看,属性就像是类的成员变量,这是这个变量的变量名。
type1, type2 数组属性的下标类型,允许任何有效的变量类型作为数组的下标。
attributes 属性的参数,包含以下表格里面的至少一个项目,每个项目之间用英文标点逗号 “,” 隔开

属性的参数 描述
read = FGet FGet 为成员变量或成员函数,读取属性,就相当于读取这个成员变量或调用这个成员函数。
 • 如果 FGet 是成员变量,必须和属性的变量类型相同,即上面表格里面的 type 类型的:
   type FGet;
 • 如果 FGet 是成员函数,返回值必须和属性的变量类型相同,如果是数组属性,参数必须是 type1, type2 类型的:
   type FGet(void);
   type FGet(type1 p1);
   type FGet(type1 p1, type2 p2);
write = FSet FSet 为成员变量或成员函数,写入属性,就相当于写入这个成员变量或调用这个成员函数。
 • 如果 FSet 是成员变量,必须和属性的变量类型相同,即上面表格里面的 type 类型的:
   type FSet;
 • 如果 FSet 是成员函数,参数必须和属性的变量类型相同,数组属性要先写下标类型的参数,后写属性值参数:
   void FSet(type v);
   void FSet(type1 p1, type v);
   void FSet(type1 p1, type2 p2, type v);
index = v v 必须是整数常数值
一般是把数组属性当中的一个元素作为独立的属性使用的,v 值为这个元素在数组里面的下标值,例如:
public:
  __property float Value[int] = { read = FGetValue , write = FSetValue };
  __property float ValueA     = { read = FGetValue , write = FSetValue , index = 0 };
  __property float ValueB     = { read = FGetValue , write = FSetValue , index = 1 };
private:
  float FGetValue(int i);
  void FSetValue(int i, float v);
ValueA 就相当于 Value[0]; ValueB 就相当于 Value[1];
a = ValueA 就相当于 a = FGetValue(0); ValueB = b 就相当于 FSetValue(1, b);
stored = v v 必须是 true 或 false。默认值是 true,如果 attributes 里面没有包含这个参数,认为这个参数的值为 true.
 • 只有这个类是一个控件的时候,这个参数才有用,是这个控件的这个属性的值是否保存到 .dfm 或 .fmx 文件里面;
 • 只有从 TObject 继承过来的类才可以包含这个参数,否则认为语法错误(无法生成控件,这参数就没有意义)。
default = v v 是和 type 相同类型的常数,是这个属性的默认值。
 • 只有这个类是一个控件的时候,这个参数才有用:
   · 如果属性值等于 v,这个属性值不储存在 .dfm 或 .fmx 文件里面,而使用内定的默认值,
     如果这个类对这个属性初始化的默认值和 v 值不同,会引起错误的结果;
   · 如果属性值不等于 v,这个属性的值储存在 .dfm 或 .fmx 文件里面;
 • 只有从 TObject 继承过来的类才可以包含这个参数,否则认为语法错误(无法生成控件,这参数就没有意义)。
nodefault 没有默认值,和 stored = true 的功能差不多,如果没有默认值,那么这个属性值会储存到 .dfm 或 .fmx 文件里面。
 • 只有这个类是一个控件的时候,这个参数才有用;
 • 只有从 TObject 继承过来的类才可以包含这个参数,否则认为语法错误(无法生成控件,这参数就没有意义)。

属性的例子:

class MyClassA
{
public:
  __property int Number = { read = FNumber };
  __property float Value = { read = FGetValue, write = FSetValue };
private:
  int FNumber;
  float FGetValue(void);
  void FSetValue(float v);
};

属性 Number 和 Value:

MyClassA a;
a.Number 在类的外部访问就是一个只读的数值了,在类的内部只能通过 FNumber 来改变这个属性的值
float f = a.Value; 执行的是 f = a.FGetValue();
a.Value = f; 执行的是 a.FSetValue(f);

Copyright © Victor Chen, http://www.cppfans.com/

M: 方法,类的成员函数

在 C++ Builder 里面,类的成员函数称为 PME 模型的 “方法”。

这些成员函数就和普通的类的成员函数一样,没有什么区别。

 

E: 事件,__closure 关键字

使用 __closure 描述的函数指针是指向类的成员函数的指针,例如:
  void (__closure *lpFunction)(String s);

类的成员函数指针,即 __closure 指针作为类的方法的回调函数,这些 __closure 指针用 __property 声明为属性,就称为 “事件”。

例如:
  TClassA 里面的
  __property void (__closure *MyEvent)(String s) = { read = lpFunction, write = lpFunction };

__closure 是修饰指针的,例如:
  void __fastcall (__closure *lpfnMyEvent)(TObject *Sender); // 正确
  void __fastcall __closure (*lpfnMyEvent)(TObject *Sender); // 错误
  void (__fastcall __closure *lpfnMyEvent)(TObject *Sender); // 错误

class TClassA
{
private:
  void (__closure *lpFunction)(String s);
public:
  __property void (__closure *MyEvent)(String s) = { read = lpFunction, write = lpFunction };
  TClassA();
  void MyFunc(String s);
};

TClassA::TClassA()
{
  lpFunction = NULL;
}

void TClassA::MyFunc(String s)
{
  if(lpFunction)
    lpFunction(s);
}

TClassA 里面的 MyEvent,可以指向 TClassB 定义的对象的 FuncB 函数

class TClassB
{
public:
  void FuncB(String s);
};

void TClassB::FuncB(String s)
{
  ShowMessage(L"TClassB::FuncB: "+s);
}

下面就是一段测试代码,执行 A.MyFunc(L"Hello!"); 执行了 B.FuncB(L"Hello!");
执行结果就是:弹出了显示 L"TClassB::FuncB: Hello!" 的信息提示框。

  TClassA A;
  TClassB B;
  A.MyEvent = B.FuncB;
  A.MyFunc(L"Hello!");
下一页:判断编译器版本

C++ 爱好者 -- Victor Chen 的个人网站 www.cppfans.com 辽ICP备11016859号