by Yazy -- 2005,04.21
构件、高级面对象的核心是:通过已经编绎代码,生成对象,该对象与源代
码的定义具有完全一致的语意。这样一种创建对象的能力降低了组件复用的
复杂性。(我这里所用的“高级”是指“具有运行时特性的”)。
比如一个使用C++语言定义的类:
class Widget
{
private:
int _number;
string _name;
public:
Widget(int number, const string& name)
: _number(number), _name(name) {}
int getNumber()
{
return _number;
}
const string& getName()
{
return _name;
}
};
如果将其发布为二进制组件(如DLL),那么要通过该二进制组件创建 Widget
的一个实例的话,我们必须要知道 Widget 类的声明才可以做到。亦即,如果
要复用一个二进制组件(如DLL)里的对象,我们必须要清楚地知道该对象的
原始结构。如果是C++语言,我们可以使用 C/C++ 的头文件来描述 DLL 文件里
类型的结构,配合头文件与 DLL 文件可在新的 C++ 源代码里创建对象。
但是头文件始终是 C++ 源程序的一部分,而且对于创建类型的对象来说还是很
累赘。重要的是这种复用二进制组件的方式还是静态完成的,即在源代码编绎
之时完成的。
高级的面向对象更希望的是在程序运行之时,可以创建一个二进制组件里的类
型,这种创建过程不需要编绎器或者最好不需要第三方工具的参与,更加不需
要“头文件”这样累赘文件。
C++的抽象数据类型没办法进行自描述,其语义需要其声明代码来描述,而且这
些描述只在源代码中有效,源代码编绎之后,其抽象数据类型的语义便不复存
在。所以在新的 C++ 源代码里使用一个 DLL 文件里的类型时,必须使用头文
件附上该类型的声明,如此才可以创建类型的实例。
所以“C++的面向对象特性只在编绎时期有效”。原因便是C++的 class 没办法
进行自描述。这种自描述特性要求类的一个实例在运行时可以被认识到其语义,
即运行时代码可以通过某个对象或者其引用掌握到该对象的类的所有信息,即“
该对象是由什么类创建的”(这有别于“通过二进制组件创建类型的实例”)。
在COM中类的语义信息通过接口定义语言描述,程序编绎时将这些描述附到 DLL
文件或者其它一些共享区域(如注册表)当中,我们可以通过这些信息来创建
DLL里类型的实例。.NET运行库使用“元数据(Meta Data)”来描述这些信息。
这些描述信息的作用相当于下面的一个声明,它可以用于描述一个DLL中Widget
的语义:
class Widget
{
private:
int _number;
string _string;
public:
Widget(int, const string&);
int getNumber();
const string& getName();
};
.NET的“元数据”还支持运行时对象的类型识别,不知COM、DCOM、COM+是否支
持,或者其它标准,如CORBAR、SOM支持不?有待学习……