BEA Logo BEA BEA Tuxedo Release [Release Number]

  BEA Home  |  Events  |  Solutions  |  Partners  |  Products  |  Services  |  Download  |  Developer Center  |  WebSUPPORT

 

   BEA Tuxedo Doc Home   |   CORBA Programming Reference   |   Previous Topic   |   Next Topic   |   Contents   |  

Mapping of OMG IDL Statements to C++

 

This chapter discusses the mappings from OMG IDL statements to C++.

Note: Some of the information in this chapter is taken from the Common Object Request Broker: C++ Language Mapping Specification, June 1999, published by the Object Management Group (OMG). Used with permission of the OMG.

 


Mappings

OMG IDL-to-C++ mappings are described for the following:

In addition, the following topics are discussed:

Data Types

Each OMG IDL data type is mapped to a C++ data type or class.

Basic Data Types

The basic data types in OMG IDL statements are mapped to C++ typedefs in the CORBA module, as shown in Table 13-1.

Table 13-1 Basic OMG IDL and C++ Data Types

OMG IDL

C++

C++ Out Type

short

CORBA::Short

CORBA::Short_out

long

CORBA::Long

CORBA::Long_out

unsigned short

CORBA::UShort

CORBA::UShort_out

unsigned long

CORBA::ULong

CORBA::ULong_out

float

CORBA::Float

CORBA::Float_out

double

CORBA::Double

CORBA::Double_out

char

CORBA::Char

CORBA::Char_out

boolean

CORBA::Boolean

CORBA::Boolean_out

octet

CORBA::Octet

CORBA::Octet_out

wchar

CORBA::WChar

CORBA::WChart_out


 
 

Note: On a 64-bit machine where a long integer is 64 bits, the definition of CORBA::Long would still refer to a 32-bit integer.

Complex Data Types

Object, pseudo-object, and user-defined types are mapped as shown in Table 13-2.

Table 13-2 Object, Pseudo-object, and User-defined OMG IDL and C++ Types

OMG IDL

C++

Object

CORBA::Object_ptr

struct

C++ struct

union

C++ class

enum

C++ enum

string

char *

wstring

CORBA::WChar *

sequence

C++ class

array

C++ array


 
 

The mapping for strings and UDTs is described in more detail in the following sections.

Strings

A string in OMG IDL is mapped to char * in C++. Both bounded and unbounded strings are mapped to char *. CORBA strings in C++ are NULL-terminated and can be used wherever a char * type is used.

If a string is contained within another user-defined type, such as a struct, it is mapped to a CORBA::String_var type. This ensures that each member in the struct manages its own memory.

Strings must be allocated and deallocated using the following member functions in the CORBA class:

Note: The string_alloc function allocates len+1 characters so that the resulting string has enough space to hold a trailing NULL character.

wchars

OMG IDL defines a wchar data type that encodes wide characters from any character set. As with character data, an implementation is free to use any code set internally for encoding wide characters, though, again, conversion to another form may be required for transmission. The size of wchar is implementation-dependent.

The syntax for defining a wchar is:

<wide_char_type> ::= "wchar"

A code example for wchar is:

wchar_t wmixed[256];

Note: The wchar and wstring data types enable users to interact with computers in their native written language. Some languages, such as Japanese and Chinese, have thousands of unique characters. These character sets do not fit within a byte. A number of schemes have been used to support multi-byte character sets, but they have proved to be unwieldy to use. Wide characters and wide strings make it easier to interact with this kind of complexity.

wstrings

The wstring data type represents a sequence of wchar, except the wide character NULL. The type wstring is similar to that of type string, except that its element type is wchar instead of char. The actual length of a wstring is set at run time and, if the bounded form is used, must be less than or equal to the bound.

The syntax for defining a wstring is:

<wide_string_type> ::= "wstring" "<" <positive_int_const> ">"
| "wstring

A code example for wstring is:

CORBA::WString_var v_upper = CORBA::wstring_dup(wmixed);

wstring types are built in types just like unsigned long, char, string, double, etc. They can be used directly as parameters, typedef'd, used to construct structs, sequences, unions, arrays, and so forth.

Note: The wchar and wstring data types enable users to interact with computers in their native written language. Some languages, such as Japanese and Chinese, have thousands of unique characters. These character sets do not fit within a byte. A number of schemes have been used to support multi-byte character sets, but they have proved to be unwieldy to use. Wide characters and wide strings make it easier to interact with this kind of complexity.

Constants

A constant in OMG IDL is mapped to a C++ const definition. For example, consider the following OMG IDL definition:

    // OMG IDL
    const string CompanyName = "BEA Systems Incorporated";
    module INVENT
{
const string Name = "Inventory Modules";
        interface Order
{
const long MAX_ORDER_NUM = 10000;
};
};

This definition maps to C++ as follows:

    // C++
    const  char *const  
CompanyName = "BEA Systems Incorporated";
. . .
class INVENT
{
static const char *const Name;
. . .
        class Order : public virtual CORBA::Object
{
static const CORBA::Long MAX_ORDER_NUM;
. . .
};
};

Top-level constants are initialized in the generated .h include file, but module and interface constants are initialized in the generated client stub modules.

The following is an example of a valid reference to the MAX_ORDER_NUM constant, as defined in the previous example:

CORBA::Long accnt_id = INVENT::Order::MAX_ORDER_NUM;

Enums

An enum in OMG IDL is mapped to an enum in C++. For example, consider the following OMG IDL definition:

    // OMG IDL
    module INVENT
{
enum Reply {ACCEPT, REFUSE};
}

This definition maps to C++ as follows:

    // C++
    class INVENT
{
. . .
        enum  Reply {ACCEPT, REFUSE};
};

The following is an example of a valid reference to the enum defined in the previous example. You refer to enum as follows:

    INVENT::Reply accept_reply;
accept_reply = INVENT::ACCEPT;

Structs

A struct in OMG IDL is mapped to a C++ struct.

The generated code for a struct depends upon whether it is fixed-length or variable-length. For more information about fixed-length versus variable-length types, see the section Fixed-length Versus Variable-length User-defined Types.

Fixed-length Versus Variable-length Structs

A variable-length struct contains an additional assignment operator member function to handle assignments between two variable-length structs.

For example, consider the following OMG IDL definition:

    // OMG IDL
    module INVENT
{
// Fixed-length
struct Date
{
long year;
long month;
long day;
};

// Variable-length
struct Address
{
string aptNum;
string streetName;
string city;
string state;
string zipCode;
};
};

This definition maps to C++ as follows:

    // C++
    class INVENT
{
struct Date
{
CORBA::Long year;
CORBA::Long month;
CORBA::Long day;
};
         struct  Address
{
CORBA::String_var aptNum;
CORBA::String_var streetName;
CORBA::String_var city;
CORBA::String_var state;
CORBA::String_var zipCode;
Address &operator=(const Address &_obj);
};

};

Member Mapping

Members of a struct are mapped to the appropriate C++ data type. For basic data types (long, short, and so on), see Table 13-1. For object references, pseudo-object references, and strings, the member is mapped to the appropriate var class:

All other data types are mapped as shown in Table 13-2.

No constructor for a generated struct exists, so none of the members are initialized. Fixed-length structs can be initialized using aggregate initialization. For example:

INVENT::Date a_date = { 1995, 10, 12 };

Variable-length members map to self-managing types; these types have constructors that initialize the member.

Var

A var class is generated for structs. For more information, see the section Using var Classes.

Out

An out class is generated for structs. For more information, see the section Using out Classes.

Unions

A union in OMG IDL is mapped to a C++ class. The C++ class contains the following:

For example, consider the following OMG IDL definition:

    // OMG IDL
    union OrderItem switch (long)
{
case 1: itemStruct itemInfo;
case 2: orderStruct orderInfo;
default: ID idInfo;
};

This definition maps to C++ as follows:

    // C++
   class OrderItem
{
public:
OrderItem();
OrderItem(const OrderItem &);
~OrderItem();

OrderItem &operator=(const OrderItem&);
           void  _d  (CORBA::Long);
CORBA::Long _d () const;

void itemInfo (const itemStruct &);
const itemStruct & itemInfo () const;
itemStruct & itemInfo ();

void orderInfo (const orderStruct &);
const orderStruct & orderInfo () const;
orderStruct & orderInfo ();

void idInfo (ID);
ID idInfo () const;

. . .
};

The default union constructor does not set a default discriminator value for the union; therefore, you cannot call any union accessor member function until you have set the value of the union. The discriminator is an attribute that is mapped through the _d member function.

Union Member Accessor and Modifier Member Function Mapping

For each member in the union, accessor and modifier member functions are generated.

In the following code, taken from the previous example, two member functions are generated for the ID member function:

     void idInfo (ID);
ID idInfo () const;

In this example, the first function (the modifier) sets the discriminator to the default value and sets the value of the union to the specified ID value. The second function, the accessor, returns the value of the union.

Depending upon the data type of the union member, additional modifier functions are generated. The member functions generated for each data type are as follows:

Var

A var class is generated for a union. For more information, see the section Using var Classes .

Out

An out class is generated for a union. For more information, see the section Using out Classes.

Member Functions

In addition to the accessor and modifiers, the following member functions are generated for an OMG IDL union of type TYPE with switch (long) discriminator:

TYPE();

This is the default constructor for a union. No default discriminator is set by this function, so you cannot access the union until you set the value of the union.

TYPE( const TYPE & From);

This copy constructor deep copies the specified union. Any data in the union parameter is copied. The From argument specifies the union to be copied.

~TYPE();

This destructor frees the data associated with the union.

TYPE &operator=(const TYPE & From);

This assignment operator copies the specified union. Any existing value in the current union is freed. The From argument specifies the union to be copied.

void _d (CORBA::Long Descrim);

This member function sets the value of the discriminant and frees the current value. The Descrim argument specifies the new discriminant. The data type of the argument is determined by the OMG IDL data type specified in the switch statement of the union. For each OMG IDL data type, see Table 13-1 for the C++ data type.

CORBA::Long _d () const;

This function returns the current discriminant value. The data type of the return value is determined by the OMG IDL data type specified in the switch statement of the union. For each OMG IDL data type, see Table 13-1 for the C++ data type.

Sequences

A sequence in OMG IDL is mapped to a C++ class. The C++ class contains the following:

You must set the length before accessing any elements.

For example, consider the following OMG IDL definition:

// OMG IDL
module INVENT 
{
. . .
typedef sequence<LogItem> LogList;
}

This definition maps to C++ as follows:

// C++
class LogList
{
public:
// Default constructor
LogList();
        // Maximum constructor
LogList(CORBA::ULong _max);
       // TYPE * data constructor
LogList
(
CORBA::ULong _max,
CORBA::ULong _length,
LogItem *_value,
CORBA::Boolean _relse = CORBA_FALSE
);
        // Copy constructor
LogList(const LogList&);
        // Destructor 
~LogList();
        LogList &operator=(const LogList&);
        CORBA::ULong maximum() const;
        void length(CORBA::ULong);
CORBA::ULong length() const;
        LogItem &operator[](CORBA::ULong _index);
const LogItem &operator[](CORBA::ULong _index) const;
        static LogItem *allocbuf(CORBA::ULong _nelems);
static void freebuf(LogItem *);
};
    };

Sequence Element Mapping

The operator[] functions are used to access or modify the sequence element. These operators return a reference to the sequence element. The OMG IDL sequence base type is mapped to the appropriate C++ data type.

For basic data types, see Table 13-1. For object references, TypeCode references, and strings, the base type is mapped to a generated _ForSeq_var class. The _ForSeq_var class provides the capability to update a string or an object that is stored within the sequence. This generated class has the same member functions and signatures as the corresponding var class. However, this _ForSeq_var class honors the setting of the release parameter in the sequence constructor. The distinction is that the _ForSeq_var class lets users specify the Release flag, thereby allowing users to control the freeing of memory.

All other data types are mapped as shown in Table 13-2.

Vars

A var class is generated for a sequence. For more information, see the section Using var Classes.

Out

An out class is generated for a sequence. For more information, see the section Using out Classes.

Member Functions

For a given OMG IDL sequence SEQ with base type TYPE, the member functions for the generated sequence class are described as follows:

SEQ ();

This is the default constructor for a sequence. The length is set to 0 (zero). If the sequence is unbounded, the maximum is also set to 0 (zero). If the sequence is bounded, the maximum is specified by the OMG IDL type and cannot be changed.

SEQ (CORBA::ULong Max);

This constructor is present only if the sequence is unbounded. This function sets the length of the sequence to 0 (zero) and sets the maximum of the buffer to the specified value. The Max argument specifies the maximum length of the sequence.

SEQ (CORBA::ULong Max, CORBA::ULong Length, TYPE * Value,
CORBA::Boolean Release);

This constructor sets the maximum, length, and elements of the sequence. The Release flag determines whether elements are released when the sequence is destroyed. Explanations of the arguments are as follows:

Max

The maximum value of the sequence. This argument is not present in bounded sequences.

Length

The current length of the sequence. For bounded sequences, this value must be less than the maximum specified in the OMG IDL type.

Value

A pointer to the buffer containing the elements of the sequence.

Release

Determines whether elements are released. If this flag has a value of CORBA_TRUE, the sequence assumes ownership of the buffer pointed to by the Value argument. If the Release flag is CORBA_ TRUE, this buffer must be allocated using the allocbuf member function, because it will be freed using the freebuf member function when the sequence is destroyed.

SEQ(const S& From);

This copy constructor deep copies the sequence from the specified argument. The From argument specifies the sequence to be copied.

~SEQ();

This destructor frees the sequence and, depending upon the Release flag, may free the sequence elements.

SEQ& operator=(const SEQ& From);

This assignment operator deep copies the sequence from the specified sequence argument. Any existing elements in the current sequence are released if the Release flag in the current sequence is set to CORBA_TRUE. The From argument specifies the sequence to be copied.

CORBA::ULong maximum( ) const;

This function returns the maximum of the sequence. For a bounded sequence, this is the value set in the OMG IDL type. For an unbounded sequence, this is the current maximum of the sequence.

void length(CORBA::ULong Length);

This function sets the current length of the sequence. The Length argument specifies the new length of the sequence. If the sequence is unbounded and the new length is greater than the current maximum, the buffer is reallocated and the elements are copied to the new buffer. If the new length is greater than the maximum, the maximum is set to the new length.

For a bounded sequence, the length cannot be set to a value greater than the maximum.

CORBA::ULong length() const;

This function returns the current length of the sequence.

TYPE & operator[](CORBA::ULong Index);
const
TYPE & operator[](CORBA::ULong Index) const;

These accessor functions return a reference to the sequence element at the specified index. The Index argument specifies the index of the element to return. This index cannot be greater than the current sequence length. The length must have been set either using the TYPE * constructor or the length(CORBA::ULong) modifier. If TYPE is an object reference, TypeCode reference, or string, the return type will be a ForSeq_var class.

static TYPE * allocbuf(CORBA::ULong NumElems);

This static function allocates a buffer to be used with the TYPE * constructor. The NumElems argument specifies the number of elements in the buffer to allocate. If the buffer cannot be allocated, NULL is returned.

If this buffer is not passed to the TYPE * constructor with release set to CORBA_TRUE, it should be freed using the freebuf member function.

static void freebuf(TYPE * Value);

This static function frees a TYPE * sequence buffer allocated by the allocbuf function. The Value argument specifies the TYPE * buffer allocated by the allocbuf function. A 0 (zero) pointer is ignored.

Arrays

An array in OMG IDL is mapped to a C++ array definition. For example, consider the following OMG IDL definition:

    // OMG IDL
    module INVENT 
{
. . .
typedef LogItem LogArray[10];
};

This definition maps to C++ as follows:

    // C++
    module INVENT
{
. . .
typedef LogItem LogArray[10];
typedef LogItem LogArray_slice;
static LogArray_slice * LogArray_alloc(void);
static void LogArray_free(LogArray_slice *data);

};

Array Slice

A slice of an array is an array with all the dimensions of the original array except the first dimension. The member functions for the array-generated classes use a pointer to a slice to return pointers to an array. A typedef for each slice is generated.

For example, consider the following OMG IDL definition:

    // OMG IDL
typedef LogItem LogMultiArray[5][10];

This definition maps to C++ as follows:

    // C++
typedef LogItem LogMultiArray[5][10];
typedef LogItem LogMultiArray_slice[10];

If you have a one-dimensional array, an array slice is just a type. For example, if you had a one-dimensional array of long, an array slice would result in a CORBA::Long data type.

Array Element Mapping

The type of the OMG IDL array is mapped to the C++ array element type in the same manner as structs. For more information, see the section Member Mapping.

Vars

A var class is generated for an array. For more information, see the section Using var Classes.

Out

An out class is generated for an array. For more information, see the section Using out Classes.

Allocation Member Functions

For each array, there are two static functions for array allocation and deallocation. For a given OMG IDL type TYPE, the allocation and deallocation routines are as follows:

static TYPE_slice * TYPE_alloc(void);

This function allocates a TYPE array, returning a pointer to the allocated TYPE array. If the array cannot be dynamically allocated, 0 (zero) is returned.

static void TYPE_free(TYPE_slice * Value);

This function frees a dynamically allocated TYPE array. The Value argument is a pointer to the dynamically allocated TYPE array to be freed.

Exceptions

An exception in OMG IDL is mapped to a C++ class. The C++ class contains the following:

The generated class is similar to a variable-length structure, but with an additional constructor to simplify initialization, and with the static _narrow member function to determine the type of UserException.

For example, consider the following OMG IDL definition:

    // OMG IDL
    module INVENT
{
exception NonExist
{
ID BadId;
};
};

This definition maps to C++ as follows:

    // C++
    class INVENT
{
. . .
        class NonExist : public CORBA::UserException
{
public:
static NonExist * _narrow(CORBA::Exception_ptr);
NonExist (ID _BadId);
NonExist ();
NonExist (const NonExist &);
~NonExist ();
NonExist & operator=(const NonExist &);
void _raise ();
ID BadId;
};
};

Attributes (data members) of the Exception class are public, so you may access them directly.

Member Mapping

Members of an exception are mapped in the same manner as structs. For more information, see Member Mapping.

All exception members are public data in the C++ class, and are accessed directly.

Var

A var class is generated for an exception. For more information, see the section Using var Classes.

Out

An out class is generated for an exception. For more information, see the sectionUsing out Classes.

Member Functions

For a given OMG IDL exception TYPE, the generated member functions are as follows:

static TYPE * _narrow(CORBA::Exception_ptr Except);

This function returns a pointer to a TYPE exception class if the exception can be narrowed to a TYPE exception. If the exception cannot be narrowed, 0 (zero) is returned. The TYPE pointer is not a pointer to a new class. Instead, it is a typed pointer to the original exception pointer and is valid only as long as the Except parameter is valid.

TYPE ( );

This is the default constructor for the exception. No initialization of members is performed for fixed-length members. Variable-length members map to self-managing types; these types have constructors that initialize the member.

TYPE(member-parameters);

This constructor has an argument for each of the members in the exception. The constructor copies each argument and does not assume ownership of the memory for any argument. Building on the previous example, the signature of the constructor is:

NonExist (ID _BadId);

There is one argument for each member of the exception. The type and parameter-passing mechanism are identical to the Any insertion operator. For information about the Any insertion operator, see the section Insertion into Any.

TYPE (const TYPE & From);

This copy constructor copies the data from the specified TYPE exception argument. The From argument specifies the exception to be copied.

~TYPE ();

This destructor frees the data associated with the exception.

TYPE & operator=(const TYPE & From);

This assignment operator copies the data from the specified TYPE exception argument. The From argument specifies the exception to be copied.

void _raise ();

This function causes the exception instance to throw itself. A catch clause

can catch it by a more derived type.

Mapping of Pseudo-objects to C++

CORBA pseudo-objects may be implemented either as normal CORBA objects or as serverless objects. In the CORBA specification, the fundamental differences between these strategies are:

References to serverless objects are not necessarily valid across computational contexts; for example, address spaces. Instead, references to serverless objects that are passed as parameters may result in the construction of independent, functionally identical copies of objects used by receivers of these references. To support this, the otherwise hidden representational properties (such as data layout) of serverless objects are made known to the ORB. Specifications for achieving this are not contained in this chapter; making serverless objects known to the ORB is an implementation detail.

This chapter provides a standard mapping algorithm for all pseudo-object types. This avoids the need for piecemeal mappings for each of the nine CORBA pseudo-object types, and accommodates any pseudo-object types that may be proposed in future revisions of CORBA. It also avoids representation dependence in the C mapping, while still allowing implementations that rely on C-compatible representations.

Usage

Rather than C-PIDL, this mapping uses an augmented form of full OMG IDL to describe serverless object types. Interfaces for pseudo-object types follow the same rules as normal OMG IDL interfaces, with the following exceptions:

The pseudo prefix means that the interface may be implemented in either a normal or serverless fashion. That is, apply either the rules described in the following sections, or the normal mapping rules described in this chapter.

Mapping Rules

Serverless objects are mapped in the same way as normal interfaces, except for the differences outlined in this section.

Classes representing serverless object types are not subclasses of CORBA::Object, and are not necessarily subclasses of any other C++ class. Thus, they do not necessarily support, for example, the Object::create_request operation.

For each class representing a serverless object type T, overloaded versions of the following functions are provided in the CORBA namespace:

// C++
void release(T_ptr);
Boolean is_nil(T_ptr p);

The mapped C++ classes are not guaranteed to be usefully subclassable by users, although subclasses can be provided by implementations. Implementations are allowed to make assumptions about internal representations and transport formats that may not apply to subclasses.

The member functions of classes representing serverless object types do not necessarily obey the normal memory management rules. This is because some serverless objects, such as CORBA::NVList, are essentially just containers for several levels of other serverless objects. Requiring callers to explicitly free the values returned from accessor functions for the contained serverless objects would be counter to their intended usage.

All other elements of the mapping are the same. In particular:

Relation to the C PIDL Mapping

All serverless object interfaces and declarations that rely on them have direct analogs in the C mapping. The mapped C++ classes can, but need not, be implemented using representations compatible to those chosen for the C mapping. Differences between the pseudo-object specifications for C-PIDL and C++ PIDL are as follows:

Brief descriptions and listings of each pseudo-interface and its C++ mapping are provided in the following sections. Further details, including definitions of types referenced but not defined below, may be found in the relevant sections of this document.

Typedefs

A typedef in OMG IDL is mapped to a typedef in C++. Depending upon the OMG IDL data type, additional typedefs and member functions may be defined. The generated code for each data type is as follows:

Implementing Interfaces

An operation in OMG IDL is mapped to a C++ member function.

The name of the member function is the name of the operation. The operation is defined as a member function in both the interface class and the stub class. The interface class is virtual; the stub class inherits from the virtual class and contains the member function code from the client application stub. When an operation is invoked on the object reference, the code contained in the corresponding stub member function executes.

For example, consider the following OMG IDL definition:

// OMG IDL
module INVENT
{
interface Order
{
. . .
ItemList modifyOrder (in ItemList ModifyList);
};
};

This definition maps to C++ as follows:

// C++
class INVENT
{
. . .
    class Order : public virtual CORBA::Object
{
. . .
virtual ItemList * modifyOrder (
const ItemList & ModifyList) = 0;
};
};
class Stub_Order : public Order
{
. . .
ItemList * modifyOrder (
const ItemList & ModifyList);
};

The generated client application stub then contains the following generated code for the stub class:

// ROUTINE NAME:        INVENT::Stub_Order::modifyOrder 
//
// FUNCTIONAL DESCRIPTION:
//
// Client application stub routine for operation
// modifyOrder.
// (Interface : Order)
INVENT::ItemList * INVENT::Stub_Order::modifyOrder (
const INVENT::ItemList & ModifyList)
{
. . .
}

Argument Mapping

Each of the arguments in an operation is mapped to the corresponding C++ type as described in Table 13-1 and Table 13-2.

The parameter passing modes for arguments in an operation are described in Table 13-7 and Table 13-8.

Implementing Operations

The signature of an implementation member function is the mapped signature of the OMG IDL operation. Unlike the client side, the server-side mapping requires that the function header include the appropriate exception (throw) specification. This requirement allows the compiler to detect when an invalid exception is raised, which is necessary in the case of a local C++-to-C++ library call (otherwise, the call would have to go through a wrapper that checks for a valid exception). For example:

// IDL
interface A
{
exception B {};
void f() raises(B);
};
// C++
class MyA : public virtual POA_A
{
public:
void f() throw(A::B, CORBA::SystemException);
...
};

Since all operations and attributes may throw CORBA system exceptions, CORBA::SystemException must appear in all exception specifications, even when an operation has no raises clause.

Within a member function, the "this" pointer refers to the implementation object's data as defined by the class. In addition to accessing the data, a member function may implicitly call another member function defined by the same class. For example:

// IDL
interface A
{
void f();
void g();
};
// C++
class MyA : public virtual POA_A
{
public:
void f() throw(SystemException);
void g() throw(SystemException);
private:
long x_;
};

void
MyA::f() throw(SystemException)
{
this->x_ = 3;
this->g();
}

However, when a servant member function is invoked in this manner, it is being called simply as a C++ member function, not as the implementation of an operation on a CORBA object. In such a context, any information available via the POA_Current object refers to the CORBA request invocation that performed the C++ member function invocation, not to the member function invocation itself.

Skeleton Derivation from Object

In several existing ORB implementations, each skeleton class derives from the corresponding interface class. For example, for interface Mod::A, the skeleton class POA_Mod::A is derived from class Mod::A. These systems, therefore, allow an object reference for a servant to be implicitly obtained via normal C++ derived-to-base conversion rules:

// C++
MyImplOfA my_a; // declare impl of A
A_ptr a = &my_a; // obtain its object reference
// by C++ derived-to-base conversion

Such code can be supported by a conforming ORB implementation, but it is not required, and is thus not portable. The equivalent portable code invokes _this() on the implementation object to implicitly register it if it has not yet been registered, and to get its object reference:

// C++
MyImplOfA my_a; // declare impl of A
A_ptr a = my_a._this(); // obtain its object reference

PortableServer Functions

Objects registered with POAs use sequences of octet, specifically the PortableServer::POA::ObjectId type, as object identifiers. However, because C++ programmers often want to use strings as object identifiers, the C++ mapping provides several conversion functions that convert strings to ObjectId and vice versa:

// C++
namespace PortableServer
{
char* ObjectId_to_string(const ObjectId&);

ObjectId* string_to_ObjectId(const char*);
}

These functions follow the normal C++ mapping rules for parameter passing and memory management.

If conversion of an ObjectId to a string would result in illegal characters in the string (such as a NULL), the first two functions throw the CORBA::BAD_PARAM exception.

Modules

A module in OMG IDL is mapped to a C++ class. Objects contained in the module are defined within this C++ class. Because interfaces and types are also mapped to classes, nested C++ classes result.

For example, consider the following OMG IDL definition:

     // OMG IDL
     module INVENT
{
interface Order
{
. . .
};
};

This definition maps to C++ as follows:

     // C++
     class INVENT
{
. . .
class Order : public virtual CORBA::Object
{
. . .
}; // class Order
}; // class INVENT

Multiple nested modules yield multiple nested classes. Anything inside the module will be in the module class. Anything inside the interface will be in the interface class.

OMG IDL allows modules, interfaces, and types to have the same name. However, when generating files for the C++ language, having the same name is not allowed. This restriction is necessary because the OMG IDL names are generated into nested C++ classes with the same name; this is not supported by C++ compilers.

Note: The BEA Tuxedo OMG IDL compiler outputs an informational message if you generate C++ code from OMG IDL with an interface or type with the same name as the current module name. If you ignore this informational message and do not use unique names to differentiate the interface or type from the module name, the compiler will signal errors when compiling the generated files.

Interfaces

An interface in OMG IDL is mapped to a C++ class. This class contains the definitions of the operations, attributes, constants, and user-defined types (UDTs) contained in the OMG IDL interface.

For an interface INTF, the generated interface code contains the following items:

For example, consider the following OMG IDL definition:

     // OMG IDL
     module INVENT
{
interface Order
{
void cancelOrder ();
};
};

This definition maps to C++ as follows:

    // C++
class INVENT
{
. . .
class Order;
typedef Order * Order_ptr;
         class Order : public virtual CORBA::Object
{
. . .
static Order_ptr _duplicate(Order_ptr obj);
static Order_ptr _narrow(CORBA::Object_ptr obj);
static Order_ptr _nil();
virtual void cancelOrder () = 0;
. . .
};
};

The object reference types and static member functions are described in the following sections, as are UDTs, operations, and attributes.

Generated Static Member Functions

This section describes in detail the generated static member functions: _duplicate, _narrow, and _nil for an interface INTF.

static INTF_ptr _duplicate (INTF_ptr Obj)

This static member function duplicates an existing INTF object reference and returns a new INTF object reference. The new INTF object reference must be released by calling the CORBA::release member function. If an error occurs, a reference to the nil INTF object is returned. The argument Obj specifies the object reference to be duplicated.

static INTF_ptr _narrow (CORBA::Object_ptr Obj)

This static member function returns a new INTF object reference given an existing CORBA::Object_ptr object reference. The Object_ptr object reference may have been created by a call to the CORBA::ORB::string_to_object member function or may have been returned as a parameter from an operation.

The INTF_ptr object reference must correspond to an INTF object or to an object that inherits from the INTF object. The new INTF object reference must be released by calling the CORBA::release member function. The argument Obj specifies the object reference to be narrowed to an INTF object reference. The Obj parameter is not modified by this member function and should be released by the user when it is no longer required. If Obj cannot be narrowed to an INTF object reference, the INTF nil object reference is returned.

static INTF_ptr _nil ( )

This static member function returns the new nil object reference for the INTF interface. The new reference does not have to be released by calling the CORBA::release member function.

Object Reference Types

An interface class (INTF) is a virtual class; the CORBA standard does not allow you to:

Instead, you use one of the object reference types, INTF_ ptr or INTF_var class.
You can obtain an object reference by using the _narrow static member function. Operations are invoked on these classes using the arrow operator (->).

The INTF_var class simplifies memory management by automatically releasing the object reference when the INTF_var class goes out of scope or is reassigned. Variable types are generated for many of the UDTs and are described in Using var Classes.

Attributes

A read-only attribute in OMG IDL is mapped to a C++ function that returns the attribute value. A read-write attribute maps to two overloaded C++ functions, one to return the attribute value and one to set the attribute value. The name of the overloaded member function is the name of the attribute.

Attributes are generated in the same way that operations are generated. They are defined in both the virtual and the stub classes. For example, consider the following OMG IDL definition:

// OMG IDL
module INVENT
{
interface Order
{
. . .
attribute itemStruct itemInfo;
};
};

This definition maps to C++ as follows:

// C++
class INVENT
{
. . .
    class Item : public virtual CORBA::Object
{
. . .
virtual itemStruct * itemInfo ( ) = 0;
        virtual void itemInfo (
const itemStruct & itemInfo) = 0;
};
};
class Stub_Item : public Item
{
. . .
itemStruct * itemInfo ();
    void itemInfo (
const itemStruct & itemInfo);
};

The generated client application stub then contains the following generated code for the stub class:

// ROUTINE NAME:       INVENT::Stub_Item::itemInfo 
//
// FUNCTIONAL DESCRIPTION:
//
// Client application stub routine for attribute
// INVENT::Stub_Item::itemInfo. (Interface : Item)
INVENT::itemStruct * INVENT::Stub_Item::itemInfo ( )
{
. . .
}
//
// ROUTINE NAME: INVENT::Stub_Item::itemInfo
//
// FUNCTIONAL DESCRIPTION:
//
// Client application stub routine for attribute
// INVENT::Stub_Item::itemInfo. (Interface : Item)
void INVENT::Stub_Item::itemInfo (
const INVENT::itemStruct & itemInfo)
{
}

Argument Mapping

An attribute is equivalent to two operations, one to return the attribute and one to set the attribute. For example, the itemInfo attribute listed above is equivalent to:

void itemInfo (in itemStruct itemInfo); 
itemStruct itemInfo ();

The argument mapping for the attribute is the same as the mapping for an operation argument. The attribute is mapped to the corresponding C++ type as described in Table 13-1 and Table 13-2. The parameter passing modes for arguments in an operation are described in Table 13-7 and Table 13-8.

Any Type

An any in OMG IDL is mapped to the CORBA::Any class. The CORBA::Any class handles C++ types in a type-safe manner.

Handling Typed Values

To decrease the chances of creating an any with a mismatched TypeCode and value, the C++ function overloading facility is utilized. Specifically, for each distinct type in an OMG IDL specification, overloaded functions to insert and extract values of that type are provided. Overloaded operators are used for these functions to completely avoid any name space pollution. The nature of these functions, which are described in detail below, is that the appropriate TypeCode is implied by the C++ type of the value being inserted into or extracted from the any.

Since the type-safe any interface described below is based upon C++ function overloading, it requires C++ types generated from OMG IDL specifications to be distinct. However, there are special cases in which this requirement is not met:

Insertion into Any

To allow a value to be set in an any in a type-safe fashion, the following overloaded operator function is provided for each separate OMG IDL type T:

// C++
void operator<<=(Any&, T);

This function signature suffices for the following types, which are usually passed by value:

For values of type T that are too large to be passed by value efficiently, two forms of the insertion function are provided:

// C++
void operator<<=(Any&, const T&); // copying form
void operator<<=(Any&, T*); // non-copying form

Note that the copying form is largely equivalent to the first form shown, as far as the caller is concerned.

These "left-shift-assign" operators are used to insert a typed value into an any, as follows:

// C++
Long value = 42;
Any a;
a <<= value;

In this case, the version of operator<<= overloaded for type Long sets both the value and the TypeCode properly for the Any variable.

Setting a value in an any using operator<<= means the following:

Copying insertion of a string type causes the following function to be invoked:

// C++
void operator<<=(Any&, const char*);

Since all string types are mapped to char*, this insertion function assumes that the value being inserted is an unbounded string. Distinguishing Boolean, Octet, Char, and Bounded Strings describes how bounded strings may be correctly inserted into an Any. Noncopying insertion of both bounded and unbounded strings can be achieved using the Any::from_string helper type described in Distinguishing Boolean, Octet, Char, and Bounded Strings.

Type-safe insertion of arrays uses the Array_forany types described in Arrays. The ORB provides a version of operator<<= overloaded for each Array_forany type. For example:

// IDL
typedef long LongArray[4][5];
// C++
typedef Long LongArray[4][5];
typedef Long LongArray_slice[5];
class LongArray_forany { ... };

void operator<<=(Any &, const LongArray_forany &);

The Array_forany types are always passed to operator<<= by reference to const. The nocopy flag in the Array_forany constructor is used to control whether the inserted value is copied (nocopy == FALSE) or consumed (nocopy == TRUE). Because the nocopy flag defaults to FALSE, copying insertion is the default.

Because of the type ambiguity between an array of T and a T*, it is highly recommended that portable code explicitly use the appropriate Array_forany type when inserting an array into an Any. For example:

// IDL
struct S {... };
typedef S SA[5];
// C++
struct S { ... };
typedef S SA[5];
typedef S SA_slice;
class SA_forany { ... };

SA s;
// ...initialize s...
Any a;
a <<= s; // line 1
a <<= SA_forany(s); // line 2

Line 1 results in the invocation of the noncopying operator<<=(Any&, S*) due to the decay of the SA array type into a pointer to its first element, rather than the invocation of the copying SA_forany insertion operator. Line 2 explicitly constructs the SA_forany type and thus results in the desired insertion operator being invoked.

The noncopying version of operator<<= for object references takes the address of the T_ptr type, as follows:

// IDL
interface T { ... };
// C++
void operator<<=(Any&, T_ptr); // copying
void operator<<=(Any&, T_ptr*); // non-copying

The noncopying object reference insertion consumes the object reference pointed to by T_ptr*; therefore, after insertion the caller may not access the object referred to by T_ptr because the Any may have duplicated and then immediately released the original object reference. The caller maintains ownership of the storage for the T_ptr itself.

The copying version of operator<<= is also supported on the Any_var type.

Extraction from Any

To allow type-safe retrieval of a value from an any, the ORB provides the following operators for each OMG IDL type T:

// C++
Boolean operator>>=(const Any&, T&);

This function signature suffices for primitive types that are usually passed by value. For values of type T that are too large to be passed by value efficiently, the ORB provides a different signature, as follows:

// C++
Boolean operator>>=(const Any&, T*&);

The first form of this function is used only for the following types:

For all other types, the second form of the function is used.

This "right-shift-assign" operator is used to extract a typed value from an any, as follows:

// C++
Long value;
Any a;
a <<= Long(42);
if (a >>= value) {
// ... use the value ...
}

In this case, the version of operator>>= for type Long determines whether the Any truly does contain a value of type Long and, if so, copies its value into the reference variable provided by the caller and returns TRUE. If the Any does not contain a value of type Long, the value of the caller's reference variable is not changed, and operator>>= returns FALSE.

For nonprimitive types, extraction is done by pointer. For example, consider the following OMG IDL struct:

// IDL
struct MyStruct {
long lmem;
short smem;
};

Such a struct could be extracted from an Any as follows:

// C++
Any a;
// ... a is somehow given a value of type MyStruct ...
MyStruct *struct_ptr;
if (a >>= struct_ptr) {
// ... use the value ...
}

If the extraction is successful, the caller's pointer points to storage managed by the Any, and operator>>= returns TRUE. The caller must not try to delete or otherwise release this storage. The caller also should not use the storage after the contents of the Any variable are replaced via assignment, insertion, or the replace function, or after the Any variable is destroyed. Care must be taken to avoid using T_var types with these extraction operators, since they will try to assume responsibility for deleting the storage owned by the Any.

If the extraction is not successful, the value of the caller's pointer is set equal to the NULL pointer, and operator>>= returns FALSE.

Correct extraction of array types relies on the Array_forany types described in Arrays.

An example of the OMG IDL is as follows:

// IDL
typedef long A[20];
typedef A B[30][40][50];
// C++
typedef Long A[20];
typedef Long A_slice;
class A_forany { ... };
typedef A B[30][40][50];
typedef A B_slice[40][50];
class B_forany { ... };

Boolean operator>>=(const Any&, A_forany&); // for type A
Boolean operator>>=(const Any&, B_forany&); // for type B

The Array_forany types are always passed to operator>>= by reference.

For strings and arrays, applications are responsible for checking the TypeCode of the Any to be sure that they do not overstep the bounds of the array or string object when using the extracted value.

The operator>>= is also supported on the Any_var type.

Distinguishing Boolean, Octet, Char, and Bounded Strings

Since the Boolean, octet, and char OMG IDL types are not required to map to distinct C++ types, another means of distinguishing them from each other is necessary so that they can be used with the type-safe Any interface. Similarly, since both bounded and unbounded strings map to char*, another means of distinguishing them must be provided. This is done by introducing several new helper types nested in the Any class interface. For example, this is accomplished as shown below:

// C++
class Any
{
public:
// special helper types needed for boolean, octet,
// char, and bounded string insertion
struct from_boolean {
from_boolean(Boolean b) : val(b) {}
Boolean val;
};
struct from_octet {
from_octet(Octet o) : val(o) {}
Octet val;
};
struct from_char {
from_char(Char c) : val(c) {}
Char val;
};
struct from_string {
from_string(char* s, ULong b,
Boolean nocopy = FALSE) :
val(s), bound(b) {}
char *val;
ULong bound;
};
    void operator<<=(from_boolean);
void operator<<=(from_char);
void operator<<=(from_octet);
void operator<<=(from_string);
// special helper types needed for boolean, octet,
// char, and bounded string extraction
struct to_boolean {
to_boolean(Boolean &b) : ref(b) {}
Boolean &ref;
};
struct to_char {
to_char(Char &c) : ref(c) {}
Char &ref;
};
struct to_octet {
to_octet(Octet &o) : ref(o) {}
Octet &ref;
};
struct to_string {
to_string(char *&s, ULong b) : val(s), bound(b) {}
char *&val;
ULong bound;
};
    Boolean operator>>=(to_boolean) const;
Boolean operator>>=(to_char) const;
Boolean operator>>=(to_octet) const;
Boolean operator>>=(to_string) const;
    // other public Any details omitted
private:
// these functions are private and not implemented
// hiding these causes compile-time errors for
// unsigned char
void operator<<=(unsigned char);
Boolean operator>>=(unsigned char &) const;
};

The ORB provides the overloaded operator<<= and operator>>= functions for these special helper types. These helper types are used as shown here:

// C++
Boolean b = TRUE;
Any any;
any <<= Any::from_boolean(b);
// ...
if (any >>= Any::to_boolean(b)) {
// ...any contained a Boolean...
}

char* p = "bounded";
any <<= Any::from_string(p, 8);
// ...
if (any >>= Any::to_string(p, 8)) {
// ...any contained a string<8>...
}

A bound value of 0 (zero) indicates an unbounded string.

For noncopying insertion of a bounded or unbounded string into an Any, the nocopy flag on the from_string constructor should be set to TRUE:

// C++
char* p = string_alloc(8);
// ...initialize string p...
any <<= Any::from_string(p, 8, 1); // any consumes p

Assuming that boolean, char, and octet all map the C++ type unsigned char, the private and unimplemented operator<<= and operator>>= functions for unsigned char cause a compile-time error if straight insertion or extraction of any of the boolean, char, or octet types is attempted:

// C++
Octet oct = 040;
Any any;
any <<= oct; // this line will not compile
any <<= Any::from_octet(oct); // but this one will

Widening to Object

Sometimes it is desirable to extract an object reference from an Any as the base Object type. This can be accomplished using a helper type similar to those required for extracting boolean, char, and octet:

// C++
class Any
{
public:
...
struct to_object {
to_object(Object_ptr &obj) : ref(obj) {}
Object_ptr &ref;
;
Boolean operator>>=(to_object) const;
...
};

The to_object helper type is used to extract an object reference from an Any as the base Object type. If the Any contains a value of an object reference type as indicated by its TypeCode, the extraction function operator>>=(to_object) explicitly widens its contained object reference to Object and returns TRUE; otherwise, it returns FALSE. This is the only object reference extraction function that performs widening on the extracted object reference. As with regular object reference extraction, no duplication of the object reference is performed by the to_object extraction operator.

Handling Untyped Values

Under some circumstances the type-safe interface to Any is not sufficient. An example is a situation in which data type