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.
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.
Whenever it maps an IDL string to a
char *, 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.
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);
...
};
...
};
const string str_example = this is an example;
const
long long_example = 100;
const
boolean bool_example = TRUE;
};
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 */
...
};
const char *example::str_example = this is an example;
const CORBA::Long example::long_example = 100;
const
CORBA::Boolean example::bool_example = 1;
typedef octet example_octet;
typedef enum
enum_values {
first,
second,
third
}
enum_example;
typedef octet example_octet;
enum
enum_values {
first,
second,
third
};
typedef
enum_values enum_example;
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;
typedef sequence<long> S1;
typedef
S1 S2;
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;
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.
•
|
string type, bounded or unbounded
|
•
|
Other structures or unions that contain a variable-length member
|
•
|
array with variable-length elements
|
•
|
typedef with variable-length elements.
|
|
|
|
|
|
|
|
|
|
|
|
array, array_slice, array_forany, and array_var
|
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.
struct example {
short a;
long b;
};
struct example {
CORBA::Short a;
CORBA::Long b;
};
class
example_var
{
...
private:
example *_ptr;
};
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.
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;
interface ABC {
...
};
struct
vexample {
short a;
ABC c;
string name;
};
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.
The use of _var classes in variable-length structures ensures that memory allocated to the variable-length members is managed transparently.
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.
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
};
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);
...
};
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.
•
|
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.
|
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;
};
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.
•
|
Always use allocbuf and freebuf to create and free storage used with sequences.
|
typedef sequence<string, 3>
String_seq;
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);
interface Intf
{
...
};
typedef
long L[10];
typedef
string S[10];
typedef
Intf A[10];
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.
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.
typedef long L[10];
typedef
string str[1][2][3];
•
|
operator[] is overloaded to provide intuitive access to array elements.
|
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;
};
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.
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;
};
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
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.
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.
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 *.
The C++ interfaces for the DerivedExample class are as follows:
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.
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.
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.
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.