This chapter contains C++ coding examples. It has the following major sections:
“cfront Compatibility Examples” provides you with examples of code that compiled with cfront, but are invalid in the Silicon Graphics C++ environment.
This section contains examples of cfront-compatible code that is illegal in the Silicon Graphics C++ environment. (For a complete description of the cfront compatibility issues, see “cfront Compatibility”.) The examples covered are listed below:
Terminating comment lines with a backslash
Explicitly declaring member functions
Using the same identifier for multiple arguments
Deleting a pointer to a const
Passing a pointer to volatile data
Disambiguating between a char* and a long
Rejecting redundant type specifiers
Converting a pointer to a class to an accessible base class
Assigning a 0 to a pointer
If you use a C++-style (//) comment line terminated with a backslash, CC and DCC will (correctly) continue the comment line into the next source line. OCC (which uses the UNIX® standard cpp) incorrectly terminates the comment at the end of the line. This may cause hard-to-find bugs.
In Example 6-1, CC and DCC considers the two lines following the // comment to be part of the comment, while cfront does not.
#include <stdio.h>
int macro() { return 0; }
// Continued comment...............\
#define macro() \
(printf( “FAIL: executed a comment!\n” ), 1 )
int main()
{
return macro();
}
|
cfront (incorrectly) calls the macro and DCC calls the function. You must delete the backslash at the end of the comment line.
You must have an explicit declaration of a member function in a class if there is an explicit definition of it outside the class. cfront allows this, but CC and DCC displays the following error message:
error(3414): defining an implicitly declared member function is not allowed alpha::alpha( const alpha &other )
^
|
For example, the code in Example 6-2 will not compile.
class alpha
{
public:
virtual void func(); // Needed to get implicit constructor
long member; // No constructor, so not initialized
};
alpha::alpha( const alpha &other )
{
member = other.member + 1000;
}
|
You must explicitly declare the missing member function and provide the default constructor.
You may not delete a pointer to a const. (If the pointer is to a type other than the class itself, cfront also issues an error message.) If you do so, the following error message is displayed:
error(3352): a pointer to const may not be deleted
delete ptr; // Error 352.
^
|
For example, the code in Example 6-3 will not compile.
class Foo
{
public:
Foo();
Foo( int );
~Foo();
private:
int stuff;
const Foo* ptr;
};
Foo::~Foo()
{
delete ptr; // Error 352.
}
|
You must cast the pointer to a non-const type.
You may not pass a pointer to volatile data to a function that is expecting a pointer to non-volatile data. If you do so, the following error message is displayed:
error(3252): argument of type “volatile mytype *” is
incompatible with parameter of type “mytype *”
f1( vol ); // Error.
^
|
For example, the code in Example 6-4 will not compile.
typedef struct
{
long i;
long j;
} mytype;
void f1( mytype* );
void f2( int* );
volatile mytype *vol;
volatile int *pvi;
int main()
{
f1( vol ); // Error.
f2( pvi ); // Error.
return 0;
}
|
One solution is to cast the actual expression to the type expected, though that may result in incorrect code, as the data is no longer treated as volatile. A better solution is to rewrite the function to accept volatile data.
When calling an overloaded function with char* and long variables and passing an integral constant 0 smaller than a long, you must explicitly cast the argument to either a char* or a long. If you do not, the following error message is displayed:
error(3390): more than one instance of constructor “UndoEvent::UndoEvent” matches the argument list: function func( char *)” function func( long)” func( (Bool)False ); |
For example, the code in Example 6-5 will not compile.
void func( char * ){}
void func( long ){}
typedef unsigned char Bool;
int main()
{
func( (Bool) 0 ); // Error 3390.
return 0;
}
|
You must use a cast to disambiguate which constructor is to be called.
You may not use redundant type specifiers. If you do so, the following error message is displayed:
error(3177): invalid combination of type specifiers
unsigned unsigned int x; // Error
^
|
For example, the code in Example 6-6 will not compile.
typedef const int Int; . . . const Int x; // Error |
You must delete the redundant type specifier.
![]() | Note: A long long data type is supported. |
You cannot implicitly cast a pointer to a class to be a pointer to a different class, except when the pointer becomes a pointer to a base-class of the original class. Even when both classes inherit from a same base class, a pointer to one of these classes cannot be implicitly cast to be a pointer to the other class. If you try to do so, the following error message is displayed:
error(135): operand types are incompatible (“D1 *” and “D2 *”)
bp = i ? dp1 : dp2; // Error.
^
|
For example, the code in Example 6-7 will not compile.
struct base { };
struct D1 : public base { };
struct D2 : public base { };
int i = 906;
base* bp = (base*) 0;
D1* dp1 = (D1*) 1;
D2* dp2 = (D2*) 2;
void main(void)
{
bp = i ? dp1 : dp2; // Error.
bp = i ? (base*)dp1 : (base*)dp2; // Work-around.
}
|
You must cast both the second and third expressions to the type of the common base class.
You cannot assign a comma expression with a rightmost expression of 0 to a pointer. If you do, the following error message is displayed:
error(611): a value of type “int” cannot be assigned to
an entity of type “int *”
p = ( 0, 0 ); // Error.
^
|
For example, the code in Example 6-8 will not compile.
void main()
{
int* p;
p = ( 0, 0 ); // Error.
}
|
You must cast the entire comma expression to the type of the pointer being assigned. You can do this by setting the macro WORKAROUND.
This section contains examples that demonstrate the unique capabilities of the DCC. (For a complete description of the cfront compatibility issues, see “Delta-Compatible Changes”.) The examples covered are listed below.
Adding members to a class
Adding new base classes
Promoting members
Overriding functions
Reordering members
These examples are for dynamic classes only. Non-dynamic classes (which is the default) do not have this facility; all changes are delta-incompatible.
DCC allows you to add both member functions and variables to a class without forcing the recompilation of any code that uses that class. This is true for public, protected, and private members. For example, you have a class Alpha defined as shown in the following code segment:
class Alpha
{
long a;
long A();
virtual long VA();
};
|
You are allowed to extend the members of Alpha without recompilation. A typical extension is shown in Example 6-9.
class Alpha
{
long a;
long a1;
long A();
virtual long VA();
virtual long VA1();
};
|
DCC allows you to reorder the members of a class. You can reorder the member variables to make more efficient use of space or to group members by their protection level. This reordering has no effect on the interface being provided by the class. For example, consider the code sample shown below:
class Alpha
{
long a;
char c;
long a1;
short s;
long A();
};
|
You can reorder the members as shown in Example 6-10.
class Alpha
{
long a;
long a1;
char c;
short s;
long A();
};
|
DCC allows you to add a new base class to a class that already exists. For example, consider the code sample shown below:
class Alpha
{
long a;
long a1;
long A();
virtual long VA();
virtual long VA1();
};
|
You are allowed to extend the classes without recompilation. A typical extension is shown in Example 6-11.
class Gamma
{
long g;
long G();
virtual long VG();
}
class Alpha : public Gamma
{
long a;
long a1;
long A();
virtual long VA();
virtual long VA1();
};
|
Class Alpha now supports the additional functionality described in class Gamma and still supports Alpha's original interface.
![]() | Note: You cannot change from single to multiple inheritance. See “Changing From Single to Multiple Inheritance” for more information. |
DCC allows you to move functionality from a derived class to a non-virtual base class, so long as its type remains identical and is not an inline function. For example, consider the code sample shown below:
class Gamma
{
long g;
long G();
virtual long VG();
}
class Alpha : public Gamma
{
long a;
long a1;
long A();
virtual long VA();
virtual long VA1();
};
|
If Alpha is derived from Gamma, you are free to move some of the members from Alpha into Gamma. The new version of Alpha still provides a compatible interface. You won't have to worry about how the functionality of Alpha is provided, only that it is provided. For example, consider the code sample shown below:
class Gamma
{
long g;
long a1;
long G();
virtual long VG();
virtual long VA1();
}
class Alpha : public Gamma
{
long a;
long A();
virtual long VA();
};
|
a1 and VA1() have been promoted from Alpha to Gamma. You can release the new versions of Alpha and Gamma without requiring the recompilation of any code that uses either class.
DCC allows you to override a function or variable independent of whether it is a member or virtual member of a class. For example, consider the code sample shown below:
class Gamma
{
long g;
long a1;
long G();
virtual long VG();
virtual long VA1();
}
class Alpha : public Gamma
{
long a;
long A();
virtual long VA();
};
|
You can change the overrides as shown in Example 6-13.
class Gamma
{
long g;
long a1;
long G();
virtual long VG();
virtual long VA1();
}
class Alpha : public Gamma
{
long a;
long a1;
long A();
virtual long VA();
long G();
long VG();
};
|
A user of Alpha should be unconcerned whether Alpha overrides the member function G() or the virtual member function VG() (originally declared in Gamma). The function that is called when invoking G() on an instance of Alpha changes, but the code still works.
This section contains examples of class modifications that are not supported by DCC. (For a complete description of the unsupported incompatible changes, see “Delta-Incompatible Changes”.) The examples covered are listed below:
Changing member declarations
Adding overloaded functions to a class
Overriding functions
Changing from single to multiple inheritance
Moving members to an enclosing class
You may not change the declaration of a member in any way (for example, changing a type from short to long). This includes types of data members, function declarations, inline function bodies, typedef declarations, and enumeration declarations.
You may not change the values of enumeration constants. For example, consider the code sample shown below:
enum color {
red,
blue
};
|
An incompatible change is shown in Example 6-14.
enum color {
red,
yellow,
blue
};
|
Another incompatible change is shown in Example 6-15.
enum color {
red = 4,
blue = 1
};
|
You may add values to an existing enumeration, provided you do not modify the values of any of the existing enumeration constants.
You may not add or remove parameters from a member function, and you may not change the return type of a function. For example, consider the code sample shown below:
class Alpha {
void f(int x);
};
|
An incompatible change is shown in Example 6-16.
class Alpha {
void f(int x, long y);
};
|
You may add a default value to an existing parameter that did not already have one (such as int x = 906).
You may not change default parameters to member functions. For example, consider the code sample shown below:
class Alpha {
void f(int x = 906);
};
|
An incompatible change is shown in Example 6-17.
class Alpha {
void f(int x = 1);
};
|
You may add an overloaded function to a class only if the function you are adding cannot possibly be called by existing code. For example, consider the code sample shown below:
class Alpha
{
void F(int);
}
|
An incompatible change is shown in Example 6-18.
class Alpha
{
void F(int);
void F(float);
}
|
Adding the function F(float) is an incompatible change, since an existing call of F(1.0), which previously invoked F(int), would still do so. This is because DCC determines the function's signature at compile time. Only the location of the function's class is left unresolved until link time.
There are two unacceptable incompatibilities when you want to override functions:
overriding a function defined in a base class with a new version in a derived class
overriding a global object in a base class when any derived classes reference that object.
You may not override an inline function defined in a base class with a new version of the function in a derived class. For example, consider the code sample shown below:
class Base
{
int test()
{
printf( “Base::test” );
}
};
class Derived : public Base
{
};
Derived Object;
main()
{
object.test();
}
|
object.test() invokes Base::test(), which is expanded inline.
Assuming these are dynamic classes, an incompatible change is shown in Example 6-19.
class Base
{
int test()
{
printf( “Base::test” );
}
};
class Derived : public Base
{
int test()
{
printf( “Derived::test” );
}
};
Derived Object;
main()
{
object.test();
}
|
Unless main() is recompiled, it will continue to call Base::test().
A global object may not be overridden in a base class, when any derived classes reference that object. For example, consider the code sample shown below:
int global;
class Alpha
{
};
class Gamma : public Alpha
{
public:
func();
};
int gamma::func()
{
return global;
}
|
An incompatible change is shown in Example 6-20.
int global;
class Alpha
{
int global;
};
int gamma::func()
{
return global;
}
|
You may not add a base class if the derived class already has exactly one base class. For example, consider the code sample shown below:
class Gamma
{
long g;
long G();
virtual long VG();
}
class Alpha : public Gamma
{
long a;
long A();
virtual long VA1();
};
|
An incompatible change is shown in Example 6-21.
class Gamma
{
long g;
long G();
virtual long VG();
}
class Beta
{
long b;
long B();
virtual long VB();
}
class Alpha : public Gamma, Beta
{
long a;
long A();
virtual long VA1();
};
|
You may add a base class if the derived class has zero, two, or more base classes (in other words, it is already participating in multiple inheritance).
You may not move a member to an enclosing class, or hide a member from an enclosing class. For example, consider the code sample shown below:
struct outer {
static int s1;
outer();
struct inner {
static int s2;
inner();
};
};
|
An incompatible change is shown in Example 6-22.
struct outer {
static int s1;
static int s2; // moved
outer();
struct inner {
inner();
static int s1; //new member
};
};
|
s2 was moved to an enclosing class, and the new s1 in inner hides the s1 from outer. Both of these changes are delta- incompatible, and you must recompile your code.