在任何项目中(亦或名字空间中)都可能存在大量的 CORBA 对象,如果所有这些对象需要有唯一的名字那么一定会有名字空间冲突。所以 IDL 允许定义模块(module),模块指定一个独立的名字空间,类似于 C++ 的名字空间的功能性。现在对于任何接口都可以指定模块,就象下面例子展示的那样:
module FruitsBasket {
interface Apple {};
interface Orange {};
};
|
在这里,我们在 FruitsBasket 模块中定义了两个对象: Apple 和 Orange。如果我们要从其他模块中引用一个对象,我们必须给出完全的对象引用,例如,从 VegetablesBasket 模块中引用 Apple 要这样做:FruitsBasket::Apple。
也可能重新打开同一个模块来增加接口定义:下面的例子严格的等价于上一个。
module FruitsBasket {
interface Apple {};
};
module FruitsBasket {
interface Orange {};
};
|
IDL象 C++ 一样也有预编译宏指令(directive): 支持 #include 和 #pragma (这些宏指令由 idl-compiler 展开)。 #include 同在 C/C++ 中有类似的语义。允许你出于清晰的目的而把在同一个模块中的不同的接口分隔在不同的文件中。
/* 这是一个 C 式样的注释 */
// 这是一个 C++ 式样的注释 : 两者都有效
// 这些代码在 apple.idl 文件中
#include "orange.idl"
module FruitsBasket
interface Apple {};
};
|
// 这些代码在 orange.idl 文件中
module FruitsBasket
interface Orange {};
};
|
因为 IDL 的主要目的是实现在不同的语言、机器和操作系统之间的可移植性,他是强类型的。这里是最基本(标准)的 CORBA 类型:
表 1-1. 基本 CORBA 类型
类型 |
意义 |
short |
16 bit signed integer |
unsigned short |
16 bit unsigned integer |
long |
32 bit signed integer |
unsigned long |
32 bit unsigned integer |
long long |
64 bit signed integer |
unsigned long long |
64 bit unsigned integer |
float |
32 bit IEEE float |
double |
64 bit IEEE float |
long double |
128 bit float |
boolean |
boolean value: TRUE or FALSE |
octet |
8 bit byte |
char |
8 bit character (ISO latin-1) |
wchar |
国际字符格式. FixMe: 谁知道这个格式? |
string |
基于 char 的字符串 |
wstring |
基于 wchar 的字符串 |
它们的使用是非常率直的: 这有一些使用了字符串和浮点类型的 IDL 接口声明:
module FruitsBasket {
interface Apple {
attribute string color;
};
interface Orange {
attribute float size;
};
}; |
每个对象得到一个浮点类型或字符串类型的属性。
有赖于const 修饰(就象在 C++ 中) IDL 允许你定义常量。这里有一些样例 IDL 代码:
module FruitsBasket {
interface Apple {
attribute string color;
const float weight = 2.3;
const string type = "sample type";
};
interface Orange {
attribute float size;
};
};
|
使用 typedef 关键字就可以定义你自己的类型(还是很象在 C 和 C++ 中)。又是一个样例代码,这里定义了一个有自定义的类型属性的 Apple 对象,自定义的类型是一个字符串。
module FruitsBasket {
typedef string fruit_type;
interface Apple {
attribute fruit_type type;
};
interface Orange {
};
};
|
我们也有标准的 C/C++ 结构,枚举和阵列。结构,枚举和定长(fixed size)阵列象 typedef 一样简直就是 C 代码:
module calendar {
enum a_month {
january, february, march, april, may, june,
july, august, september, october, december
};
enum a_day {
monday, tuesday, wednesday, thursday,
friday, saturday, sunday
};
typedef long a_year;
struct a_date {
a_day the_day;
a_month the_month;
a_year the_year;
};
interface calendar {
attribute a_date the_date;
// 一维阵列
typedef a_date a_date_array[20];
attribute a_date_array the_date_array;
// 二维阵列
typedef a_date_array a_date_array_multi[20];
attribute a_date_array_multi the_date_array_multi;
};
};
|
变长(Variable-size)阵列在 CORBA 中叫序列(sequence):
module calendar {
interface calendar {
/* 定义了一个一维 long 阵列(数组)
* 最大长度是 20.
*/
typedef sequence <long,20> array_1;
// 一个无边界的(unbounded)的一维字符串阵列
typedef sequence <string> array_2;
// 更复杂的: 一个序列的序列
// 用于模拟多维变长阵列
typedef sequence <sequence <long,20> > array_3;
};
};
|
所有这些标准的类型允许编程者定义对象的属性和方法。对象方法(函数)这样声明:
module FruitsBasket {
interface Apple {
// eat_me 方法的声明
// 有一个 boolean 变量作为参数
void eat_me (in boolean eat_yes_or_not );
// 返回 Apple 是否被吃了
boolean eaten ();
// 返回 Apple 是否被吃了
// 和吃它的人的姓和名
boolean who_ate ( out string who_surname, out string who_name );
};
};
|
除了 in 修饰,这些声明非常象 C++ 代码: 参数由 in, out, inout 三种类型之一来修饰。它们的语义如下:in 参数是客户向对象发送的数据,out 参数是对象向客户发送的数据,inout 参数先从客户发送到对象,再被返回给客户。
所有这些方法声明都是同步操作,就是说,使用这些方法意味着你的程序将等到对象应答之后才继续执行。可以定义异步的方法,这样的话调用方法的程序可以继续执行而不是在对象返回应答之前一直阻塞,异步方法的声明用关键字 oneway(单向)。
module FruitsBasket {
interface Apple {
// eat_me 方法的声明
// 有一个 boolean 变量作为参数
void eat_me (in boolean eat_yes_or_not );
// 返回 Apple 是否被吃了
// 异步方法
oneway boolean eaten ();
// 返回 Apple 是否被吃了
// 和吃它的人的姓和名
boolean who_ate ( out string who_surname, out string who_name );
};
};
|
也可以定义例外(exception)(类似于 C++ 的例外类)。
module FruitBasket {
exception no_more_fruits {
string reason;
};
interface Apple {
// 我们所希望的各种的方法
};
};
|
最终,可以象下面这样声明有能力引发(throwing)例外的方法。
module FruitsBasket {
exception no_more_fruits {
string reason;
};
interface Apple {
void eat_me (in boolean eat_yes_or_not ) raises ( no_more_fruits );
// 我们所希望的诸如此类的方法
};
};
|
象 C++ 的类(或 Java 的接口),接口可以从其他的接口继承,并且支持多继承(multiple inheritance)。语法类似于 C++ 的语法。一个重要的不同是 IDL 不支持重载或不同的方法可以有相同的名字和不同的参数说明(signature)。
module FruitsBasket {
exception no_more_fruits {
string reason;
};
interface generic_fruit {
void eat_me (in boolean eat_yes_or_not ) raises (no_more_fruits);
oneway boolean eaten ();
};
interface generic_fruit_one {
boolean who_ate ( out string who_surname, out string who_name );
};
interface Apple : generic_fruit, generic_fruit_one {
// 这里是特定于 Apple 的方法
};
};
|
我们展示了各种 IDL 类型,一些生成新的接口和属性、方法、例外的声明的方式。感兴趣的读者可以从 CORBA 标准中读到权威的 IDL 定义并且看到一些补充的类型象 any、TypeCode、union。但这些类型对于本文不是很重要的。