VisiBroker for C++ Developer’s Guide : IDL to C++ mapping

IDL to C++ mapping
This section discusses the IDL to C++ language mapping provided by the VisiBroker for C++ idl2cpp compiler, which strictly complies with the CORBA C++ language mapping specification.
Primitive data types
The basic data types provided by the Interface Definition Language are summarized in the table below. Due to hardware differences between platforms, some of the IDL primitive data types have a definition that is marked “platform dependent.” On a platform that has 64-bit integral representations, for example, the g type, would still be only 32 bits. You should refer to the included file orbtypes.h for the exact mapping of these primitive data types for your particular platform.
Caution
The IDL boolean type is defined by the CORBA specification to have only one of two values: 1 or 0. Using other values for a boolean will result in undefined behavior.
Strings
Both bounded and unbounded String types in IDL are mapped to the C++ type char *.
Note
All CORBA string types are null-terminated.
To ensure that your applications use the same memory management facilities as VisiBroker does, use the following functions to dynamically allocate and de-allocate strings:
class CORBA
{
...
static char *
string_alloc(CORBA::ULong len);
static void string_free(char *data);
...
};
CORBA::char *string_alloc(CORBA::ULong len);
Dynamically allocates a string and returns a pointer to it. Returns a NULL pointer if the allocation fails.
The length specified by the len parameter need not include the NULL terminator.
CORBA::void *string_free(char *data);
Releases the memory associated with a string that was allocated with CORBA::string_alloc.
String_var Class
Whenever it maps an IDL string to achar *, the IDL compiler also generates a String_var class that contains a pointer to the memory allocated to hold the string. When a String_var object is destroyed or goes out of scope, the memory allocated to the string is automatically freed.
Following are the members and methods in the String_var class:
class CORBA {
class String_var {
protected:
char *_p;
...
public:
String_var();
String_var(char *p);
~String_var();
String_var& operator=(const char *p);
String_var& operator=(char *p);
String_var& operator=(const String_var& s);
operator const char *() const;
operator char *();
char &operator[](CORBA::ULong index);
char operator[](CORBA::ULong index) const;

friend ostream&      operator<<(ostream&, const String_var&);
inline friend Boolean  operator==(const String_var& s1,
const String_var& s2);
...
};
...
};
Constants
IDL constants defined outside of any interface specification are mapped directly to a C++ constant declaration. For example:
This code sample shows the top-level definitions in IDL.
const string str_example = this is an example;
const long long_example = 100;
const boolean bool_example = TRUE;
This code sample shows the resulting C++ code for constants.
const char * str_example = this is an example;
const CORBA::Long long_example = 100;
const CORBA::Boolean bool_example = 1;
IDL constants defined within an interface specification are declared in the C++ include file and assigned values in the C++ source file. For example:
This code sample shows the IDL definitions from the example.idl file.
interface example {
const string str_example = this is an example;
const long long_example = 100;
const boolean bool_example = TRUE;
};
This code sample shows the C++ code generated to the example_client.hh file.
class example :: public virtual CORBA::Object
{
...
static const
char *str_example; /* this is an example */
static const CORBA::Long long_example; /* 100 */
static const CORBA::Boolean bool_example; /* 1 */
...
};
This code sample shows the C++ code generated to the example_client.cc file.
const char *example::str_example = this is an example;
const CORBA::Long example::long_example = 100;
const CORBA::Boolean example::bool_example = 1;
Special cases involving constants
Under some circumstances, the IDL compiler must generate C++ code that contains the value of an IDL constant rather than the name of the constant. For example, in the following code samples, the value of the constant length must be generated for the typedef V to allow the C++ code to compile properly.
The code sample shows the definition of an IDL constant with a value.
// IDL
interface foo {
const long
length = 10;
typedef long V[length];
};
This code sample shows the generation of an IDL constant's value in C++.
class foo : public virtual CORBA::Object
{
const CORBA::Long length;
typedef CORBA::Long V[
10];
};
Enumerations
Enumerations in IDL map directly to C++ enumerations. For example:
// IDL
enum enum_type {
first,
second,
third
};
This code sample shows the enumerations in IDL map directly to C++ enums.
// C++ code
enum enum_type {
first,
second,
third
};
Type definitions
Type definitions in IDL map directly to C++ type definitions. If the original IDL type definition maps to several C++ types, the IDL compiler generates the corresponding aliases for each type in C++. For example:
// IDL
typedef octet example_octet;
typedef enum enum_values {
first,
second,
third
} enum_example;
This code sample shows the mapping of simple type definitions from IDL to C++.
// C++
typedef octet example_octet;
enum enum_values {
first,
second,
third
};
typedef enum_values enum_example;
The following code samples provide other type definition mapping examples.
This code sample shows the IDL typedef of an interface.
// IDL
interface A1;
typedef A1 A2;
This code sample shows mapping the IDL interface type definition in C++.
// C++
class A1;
typedef A1 *A1_ptr;
typedef A1_ptr A1Ref;
class A1_var;
typedef A1 A2;
typedef A1_ptr A2_ptr;
typedef A1Ref A2Ref;
typedef A1_var A2_var;
This code sample shows the IDL typedef of a sequence.
// IDL
typedef sequence<long> S1;
typedef S1 S2;
This code sample shows mapping the IDL sequence type definition to C++.
// C++
class S1;
typedef S1 *S1_ptr;
typedef S1_ptr S1Ref;
class S1_var;
typedef S1 S2;
typedef S1_ptr S2_ptr;
typedef S1Ref S2Ref;
typedef S1_var S2_var;
Modules
The OMG IDL to C++ language mapping specifies that each IDL module be mapped to a C++ namespace with the same name. However, few compilers currently support the use of namespaces. Therefore, VisiBroker currently supports module to class mapping only. The code samples below show how VisiBroker Edition's IDL compiler maps a module definition to a class.
This code sample shows the IDL module definition.
// IDL
module ABC
{
...
};
This code sample shows the generated C++ class.
// C++
class ABC
{
...
};
Complex data types
In this section, we discuss how the following complex data types are mapped from IDL to C++:
Any type
string type, bounded or unbounded
sequence type, bounded or unbounded
Other structures or unions that contain a variable-length member
array with variable-length elements
typedef with variable-length elements.
struct (fixed length)
struct and _var class
struct (variable length)
struct and _var class
class and _var class
class and _var class
array, array_slice, array_forany, and array_var
Structures
Fixed-length structures
For each fixed-length IDL structure mapped to C++, VisiBroker Edition's IDL compiler generates a structure as well as a _var class for the structure. The code samples below show how this is done. For more information on the _var class, see “<class_name>_var” in the VisiBroker for C++ API Reference.
This code sample shows the fixed-length structure definition in IDL.
// IDL
struct example {
short a;
long b;
};
This code sample shows the mapping of a fixed-length IDL structure to C++.
// C++
struct example {
CORBA::Short a;
CORBA::Long b;
};
class example_var
{
...
private:
example *_ptr;
};
Using fixed-length structures
When accessing fields of the _var class, you must always use the -> operator. For example, the code sample below shows that to access the fields of the _var class ex2, the -> operator must always be used. When ex2 goes out of scope, the memory allocated to it will be freed automatically.
This code sample shows the use of the example structure and the example_var class.
// Declare an example struct and initialize its fields.
example ex1 = { 2, 5 };
// Declare a _var class and assign it to a newly created example structure.
// The _var points to an allocated struct with un-initialized fields.
example_var ex2 = new example;
// Initialize the fields of ex2 from ex1
ex2->a = ex1.b;
Variable length structures
The C++ code generated when a structure contains variable-length members is different from when the structure is of fixed length. For example, the code samples below show what would happen if, in the example structure described previously, the long member were replaced with a string and an object reference were added, so that example became a variable-length structure.
This code sample shows the variable length structure definitions in IDL.
// IDL
interface ABC {
...
};
struct vexample {
short a;
ABC c;
string name;
};
This code sample shows the mapping of a variable-length structure to C++.
// C++
struct vexample {
CORBA::Short a;
ABC_var c;
CORBA::String_var name;
vexample& operator=(const vexample& s);
};
class vexample_var {
...
};
Notice how the ABC object reference is mapped to an ABC_var class. In a similar fashion, the string name is mapped to a CORBA::String_var class. In addition, an assignment operator is generated for variable-length structures.
Memory management for structures
The use of _var classes in variable-length structures ensures that memory allocated to the variable-length members is managed transparently.
Unions
Each IDL union is mapped to a C++ class with methods for setting and retrieving the value of the data members. Every member in the IDL union is mapped to a set of functions that serve as accessors and mutators. A mutator function sets the value of the data member. An accessor function returns the data in the data member.
A special, pre-defined data member, named_d, of the discriminant type is also generated. The value of this discriminant is not set when the union is first created, so an application must set it before using the union. Setting any data member using one of the methods provided automatically sets the discriminant. A special accessor function, _d(), provides access to the discriminant.
For example, the code samples below show how a union, example_union, would be generated in C++:
This code sample shows the IDL union containing a struct.
// IDL
struct example_struct
{
long abc;
};
union example_union switch(long)
{
case 1: long x; // a primitive data type
case 2: string y; // a simple data type
case 3: example_struct z; // a complex data type
};
This code sample shows the mapping of an IDL union to a C++ class.
// C++
struct example_struct
{
CORBA::Long abc;
};
class example_union
{
private:
CORBA::Long _disc;
CORBA::Long _x;
CORBA::String_var _y;
example_struct _z;
public:
example_union();
~example_union();
example_union(const example_union& obj);
example_union& operator=(const example_union& obj);
void x(const CORBA::Long val);
const CORBA::Long x() const;
void y(char *val);
void y(const char *val);
void y(const CORBA::String_var& val);
const char *y() const;
void z(const example_struct& val);
const example_struct& z() const;
example_struct& z();
CORBA::Long _d();
void _d(CORBA::Long);
...
};
The table below describes some of the methods in the example_union class.
This method is used for setting the value of the discriminator. (In the case of the example, the discriminator is of type long). Note that based on the data type of the discriminator, the input argument's type will be different.
Managed types for unions
In addition to the example_union class shown in the following code sample, an example_union_var class would also be generated. See “<class_name>_var” in the VisiBroker for C++ API Reference for details on the _var classes.
Memory management for unions
Here are some important points to remember about memory management of complex data types within a union:
A char * accessor method frees any storage before ownership of the passed pointer is assumed.
Both const char * and String_var accessor methods free any old memory before the new parameter's storage is copied.
Sequences
IDL sequences, both bounded and unbounded, are mapped to a C++ class that has a current length and a maximum length. The maximum length of a bounded sequence is defined by the sequence's type. Unbounded sequences can specify their maximum length when their C++ constructor is called. The current length can be modified programmatically. The code samples below show how an IDL sequence is mapped to a C++ class with accessor methods.
When the length of an unbounded sequence exceeds the maximum length you specify, VisiBroker transparently allocates a larger buffer, copies the old buffer to the new buffer, and frees the memory allocated to the old buffer. However, no attempt is made to free unused memory if the maximum length decreases.
This code sample shows the IDL unbounded sequence.
// IDL
typedef sequence<long> LongSeq;
This code sample shows the mapping of an IDL unbounded sequence to a C++ class.
// C++
class LongSeq
{
public:
LongSeq(CORBA::ULong max=0);
LongSeq(CORBA::ULong max=0, CORBA::ULong length,
CORBA::Long *data, CORBA::Boolean release = 0);
LongSeq(const LongSeq&);
~LongSeq();
LongSeq&     operator=(const LongSeq&);
CORBA::ULong maximum() const;
void           length(CORBA::ULong len);
CORBA::ULong length() const;
const CORBA::ULong&   operator[](CORBA::ULong index) const;
...
static LongSeq        *_duplicate(LongSeq* ptr);
static void  _release(LongSeq *ptr);
static CORBA::Long    *allocbuf(CORBA::ULong nelems);
static void  freebuf(CORBA::Long *data);

private:
CORBA::Long * _contents;
CORBA::ULong _count;
CORBA::ULong _num_allocated;
CORBA::Boolean     _release_flag;
CORBA::Long _ref_count;
};
 
This constructor allows you to set the maximum length, the current length, a pointer to the data buffer associated and a release flag. If release is not zero, VisiBroker will free memory associated with the data buffer when increasing the size of the sequence. If release is zero, the old data buffer's memory is not freed. Bounded sequences have all of these parameters except for max.
Managed types for sequences
In addition to the LongSeq class shown in the code sample below, a LongSeq_var class is also generated. See “<class_name>_var” in the VisiBroker for C++ API Reference for details on the classes. In addition to the usual methods, there are two indexing methods defined for sequences.
CORBA::Long& operator[](CORBA::ULong index);
const CORBA::Long& operator[](CORBA::ULong index) const;
Memory management for sequences
You should carefully consider the memory management issues listed below. The code sample below contains sample C++ code that illustrates these points.
Always use allocbuf and freebuf to create and free storage used with sequences.
This code sample shows the IDL specification for an unbounded sequence.
// IDL
typedef sequence<string, 3> String_seq;
This code sample shows is an example of memory management with two bounded sequences.
// C++
char *static_array[] = (1, 2, 3};
char *dynamic_array = StringSeq::allocbuf(3);
// Create a sequence, release flag is set to FALSE by default
StringSeq static_seq(3, static_array);
// Create another sequence, release flag set to TRUE
StringSeq dynamic_seq(3, dynamic_array, 1);
static_seq[1] = 1; // old memory not freed, no copying occurschar *str = string_alloc(2);
dynamic_seq[1] = str; // old memory is freed, no copying occurs
Arrays
IDL arrays are mapped to C++ arrays, which can be statically initialized. If the array elements are strings or object references, the elements of the C++ array are of type _var. The following code samples show three arrays with different element types.
This code sample shows the IDL array definitions.
// IDL
interface Intf
{
...
};
typedef long L[10];
typedef string S[10];
typedef Intf A[10];
This code sample shows the mapping of IDL arrays to C++ arrays.
// C++
typedef CORBA::Long L[10];
typedef CORBA::String_var S[10];
typedef Intf_var A[10];
The use of the managed type _var for strings and object references allows memory to be managed transparently when array elements are assigned.
Array slices
The array_slice type is used when passing parameters for multi-dimensional arrays. VisiBroker's IDL compiler also generates a _slice type for arrays that contains all but the first dimension of the array. The array _slice type provides a convenient way to pass and return parameters. The following code samples show two examples of the _slice type.
This code sample shows the IDL definition of multi-dimensional arrays.
// IDL
typedef long L[10];
typedef string str[1][2][3];
This code sample shows the generation of the _slice type.
// C++
typedef CORBA::Long L_slice;
typedef CORBA::String_var str_slice[2][3];
Managed types for arrays
In addition to generating a C++ array for IDL arrays, VisiBroker's IDL compiler will also generate a _var class. This class offers some additional features for array.
operator[] is overloaded to provide intuitive access to array elements.
This code sample shows the IDL definition of an array.
// IDL
typedef long L[10];
This code sample shows the _var class generated for arrays.
// C++
class L_var
{
public:
L_var();
L_var(L_slice *slice);
L_var(const L_var& var);
~L_var();
L_var& operator=(L_slice *slice);
L_var& operator=(const L_var& var);
CORBA::Long& operator[](CORBA::ULong index);
operator L_slice *();
operator L &() const;
...
private:
L_slice *_ptr;
};
Type-safe arrays
A special _forany class is generated to handle arrays with elements mapped to the type any. As with the _var class, the _forany class allows you to access the underlying array type. The _forany class does not release any memory upon destruction because the _any type maintains ownership of the memory. The _forany class is not implemented as a typedef because it must be distinguishable from other types if overloading is to function properly.
This code sample shows the IDL array definition.
// IDL
typedef long L[10];
This code sample shows _forany class generated for an IDL array.
// C++
class L_forany
{
public:
L_forany();
L_forany(L_slice *slice);
~L_forany();
CORBA::Long& operator[](CORBA::ULong index);
const CORBA::Long& operator[](CORBA::ULong index) const;
operator L_slice *();
operator L &() const;
operator const L & () const;
operator const L& () const;
L_forany& operator=(const L_forany obj);
...
private:
L_slice *_ptr;
};
Memory management for arrays
VisiBroker's IDL compiler generates four functions for allocating, duplicating, copying, and releasing the memory associated with arrays. These functions allow the VisiBroker ORB to manage memory without having to override the new and delete operators.
This code sample shows the IDL array definition.
// IDL
typedef long L[10];
This code sample shows the methods generated for allocating and releasing array memory.
// C++
inline L_slice *L_alloc();
// Dynamically allocates array. Returns
// NULL on failure.
inline void L_free(L_slice *data);
// Releases array memory allocated with
// L_alloc.
inline void L_copy(L:slice *_to, L_slice *_from)
//Copies the contents of the _from array to the _to array
inline L_slice *L_dup(const L_slice *_date)
//Returns a new copy of _date array
Principal
A Principal represents information about client applications that are making operation requests on an object implementation. The IDL interface of Principal does not define any operations. The Principal is implemented as a sequence of octets. The Principal is set by the client application and checked by the VisiBroker ORB implementation. VisiBroker Edition for C++ treats the Principal as an opaque type and its contents are never examined by the VisiBroker ORB.
Valuetypes
An IDL valuetype is mapped to a C++ class with the same name as the IDL valuetype. This class is an abstract base class with pure virtual accessor and modifier functions corresponding to the state members of the valuetype and pure virtual functions corresponding to the operations of valuetype.
A C++ class whose name is formed by adding an “OBV_” to the fully scoped name of the valuetype provides default implementations for the accessors and modifiers of the abstract base class.
Applications are responsible for the creation of valuetype instances. After creation, these applications deal with those instances using only pointers. Unlike object references which map to C++ _ptr types that may be implemented either as actual C++ pointers or as C++ pointer-like objects, handles to C++ valuetype instances are actual C++ pointers. This helps to distinguish them from object references.
Unlike mapping for interfaces, reference counting for valuetype must be implemented by the instance of the valuetypes. The _var type for a valuetype automates the reference counting. The code sample below illustrates these features.
valuetype Example {
Short op1();
Long op2( in Example x );
Private short val1;
Public long val2;
};
The code sample below shows the C++ mapping of the IDL definition for the following three classes.
class Example : public virtual CORBA::ValueBase {
public:
virtual CORBA::Short op1() = 0;
virtual CORBA::Long op2(Example_ptr _x) = 0;
// pure virtual getter/setters for all public state
// These accessors are just like C++ union members since
// by reference accessors allow read/write access
virtual void val2(const CORBA::Long _val2) = 0;
virtual const CORBA::Long val2() const = 0;
protected:
Example() {}
virtual ~Example() {}
virtual void val1(const CORBA::Short _val1) = 0;
virtual const CORBA::Short val1() const = 0;
private:
void operator=(const Example&);
};
class OBV_Example: public virtual Example{
public:
virtual void val2(const CORBA::Long _val2) {
_obv_val2 = _val2;
}
virtual const CORBA::Long val2() const {
return _obv_val2;
}
protected:
virtual void val1(const CORBA::Short _val1) {
_obv_val1 = _val1;
}

virtual const CORBA::Short val1() const {
return _obv_val1; }
OBV_Example() {}
virtual ~OBV_Example() {}
OBV_Example(const CORBA::Short _val1,
const CORBA::Long _val2) {
_obv_val1 = _val1;
_obv_val2 = _val2;
}
CORBA::Short _obv_val1;
CORBA::Long _obv_val2;
};
class Example_init : public CORBA::ValueFactoryBase {
};
The _init class provides a way to implement a factory for the valuetypes. Since valuetypes are passed by value over the wire, the receiving end of a streamed out valuetype usually implements a factory to create a valuetype instance from the stream. Both the server and the client should implement it if there is a possibility of receiving a valuetype over the stream. The _init class, as shown in the following code sample, which must also implement create_for_unmarshal that returns a CORBA::ValueBase *.
This code sample shows the -init class example.
class Example_init_impl: public Example_init{
public:
Example_init; _impl();
virtual ~Example_init();
CORBA::ValueBase * create_for_unmarshal() {
...// return an Example_ptr
}
};
A valuetype can derive from other valuetypes as follows:
This code sample shows the IDL for the valuetype derived from other valuetypes.
valuetype DerivedExample: Example{
Short op3();
};
The C++ interfaces for the DerivedExample class are as follows:
// IDL valuetype: DerivedExample
class DerivedExample : public virtual Example {
public:
virtual CORBA::Short op3() = 0;
protected:
DerivedExample() {}
virtual ~DerivedExample() {}
private:
void operator=(const DerivedExample&);
};
class OBV_DerivedExample: public virtual DerivedExample, public virtual OBV_Example{
protected:
OBV_DerivedExample() {}
virtual ~OBV_DerivedExample() {}
};
class DerivedExample_init : public CORBA::ValueFactoryBase { };
A derived valuetype can be truncated to the base valuetype as shown in the following code sample. This is required if the receiving end of the stream does not know how to construct a derived valuetype but can construct only the base valuetype.
This code sample shows the truncated derived valuetype.
valuetype DerivedExample : truncatable Example { };
The mapping is similar to regular derived valuetypes except that extra information is added to the Type information of the DerivedExample class to indicate the truncatability to the base class Example.
A valuetype can not derive from an interface but it can support one or more interfaces by providing all the operations of the interfaces. An IDL keyword, supports, is introduced for this purpose.
This code sample shows the IDL keyword support for the derived valuetype.
interface myInterface{
long op5();
};
valuetype IderivedExample supports myInterface {
Short op6();
};
The C++ mapping for this will be as follows:
This code sample shows the C++ for the derived valuetype.
// IDL valuetype: DerivedExample
class IderivedExample : public virtual CORBA::ValueBase {
public:
virtual CORBA::Short op6() = 0;
virtual CORBA::Long op5() = 0;
protected:
IderivedExample() {}
virtual ~IderivedExample() {}
private:
void operator=(const IderivedExample&);
};
class OBV_IderivedExample: public virtual IderivedExample{
protected:
OBV_IderivedExample() {}
virtual ~OBV_IderivedExample() {}
};
For reference counting, the C++ mapping provides two standard classes. The first class is CORBA::DefaultValueRefCountBase, which serves as a base class for any application provided concrete valuetypes that do not derive from any IDL interfaces. For these kinds of valuetypes, the applications are also free to implement their own reference counting mechanisms. The second class is PortableServer::ValueRefCountBase, which must serve as a base class for any application provided a concrete valuetype class which does derive from one or more IDL interfaces.
Valuebox
A valuebox is a valuetype applied to structures, unions, any, string, basic types, object references, enums, sequence, and array types. These types do not support method, inheritance, or interfaces. A valuebox is ref counted and is derived from CORBA::DefaultValueRefCountBase. The mapping is different for different underlying types. All valuebox C++ classes provide _boxed_in(), boxed_out(), and _boxed_inout() for mapping to the underlying types. The factory for a valuebox id automatically registered by the generated stub.
See the OMG CORBA 2.3 idl2cpp specification, Chapter 1.17, for more information. The factory for a valuebox is automatically registered by the generated stub.
Abstract Interfaces
Abstract interfaces are used to determine at runtime, if an object is passed by reference (IOR) or by value (valuetype.) A prefix “abstract” is used for this purpose before an interface declaration.
This code sample shows the IDL code sample.
abstract interface foo {
Void func():
}
A valuetype that supports an abstract interface, can be passes as that abstract interface. The abstract interface is declared as follows:
valuetype vt supports foo {
...
};
Similarly, an interface that needs to be passed as an abstract interface is declared as follows:
interface intf : foo {
}
The C++ mapping for the previously declared abstract interface foo, results in the following classes:
class foo_var : public CORBA::_var{
...
}
class foo_out{
...
};
class foo : public virtual CORBA:::AbstractBase{
private:
...
void operator=(const foo&) {}
protected:
foo();
foo(const foo& ref) {}
virtual ~foo() {}
public:
static CORBA::Object* _factory():
foo_ptr _this();
static foo_ptr _nil() { ... }
static foo_ptr _narrow(CORBA::AbstractBase* _obj);
static foo_ptr _narrow(CORBA::Object_ptr _obj);
static foo_ptr _narrow(CORBA::ValueBase_ptr _obj);
virtual void func() = 0;
...
};

class _vis_foo_stub : public virtual foo, public virtual CORBA_Object {
public :
_vis_foo_stub() {}
virtual ~_vis_foo_stub() {}
...
virtual void func():
}
There is a _var class, an _out class, and a class derived from CORBA::AbstractBase that implements the methods described in the previous code samples.