United States

Compaq C++

# Compaq C++
Using Compaq C++ for OpenVMS VAX

Previous | Contents | Index

# Chapter 4
Porting to Compaq C++

Compaq C++ implements the C++ language as defined in The Annotated C++ Reference Manual, and closely follows that text's language definition. Strict adherence to these definitions helps you produce cleaner program code.

This chapter describes ways to avoid having the Compaq C++ compiler reject program code that previously worked with other C++ implementations that adhere less strictly to the C++ language definition. References to applicable portions of The C++ Programming Language, 2nd Edition indicate where you can find additional help.

For compatability with certain C++ compilers, Compaq C++ supports the `/standard` qualifier to the `cxx` command. This option directs the compiler to interpret the source program according to certain rules followed by other implementations of the C++ language. For more information, see Section 2.1.

# 4.1 Using Classes

This section discusses porting issues pertaining to C++ classes.

## 4.1.1 Friend Declarations

When declaring friends, use the elaborated form of type specifier. The following code fragment implements the legal declaration and comments out the illegal declaration of `friend` :

    class Y;
    class Z;
    class X;
       //friend Y;  ** not legal
       friend class Z; // legal
    };

## 4.1.2 Member Access

Compaq C++ enforces accessibility rules for `public` , `protected` , and `private` members of a base class. For more information, see §r.11.2 of The C++ Programming Language, 2nd Edition.

## 4.1.3 Base Class Initializers

Unlike some older C++ implementations, Compaq C++ requires you to use the base class name in the initializer for a derived class. The following code fragment implements a legal initializer and comments out an illegal initializer:

    class Base {
        // ...
    public:
        Base (int);
    };
    class Derived : public Base {
        // ...
    public:
        // Derived(int i) : (i)  {/* ...*/}    ** not legal
        Derived(int i) : Base(i) {/* ...*/} // ** legal, supplies class name
    };

For more information, see §r.12.6.2 and §r.18.3.2 of The C++ Programming Language, 2nd Edition.

## 4.1.4 Undefined Global Symbols for Static Data Members

When a static data member is declared, the Compaq C++ compiler issues a reference to the external identifier in the object code, which must be resolved by a definition. On OpenVMS systems, the Compaq C++ compiler does not support the declaration anachronism shown in §r.18.3 of The C++ Programming Language, 2nd Edition. For example, consider the following code fragment:

    class C {
            static int i;
            };
    //missing definition
    //int C::i = 5;

    main () {}

The Compaq C++ compiler does not issue any messages during compilation; however, when you attempt to link a program containing this code, the linker issues a message similar to the following:

    %LINK-W-NUDFSYMS, 1 undefined symbol:
    %LINK-I-UDFSYM,         I__1C

# 4.2 Using Pointers

This section demonstrates how to use pointers effectively in Compaq C++.

## 4.2.1 Pointer Conversions

In Compaq C++, you cannot implicitly convert a `const` pointer to a nonconstant pointer. For example, `char **` and `const char **` are not equivalent; explicitly performing such a cast can lead to unexpected results.

For more information, see §r.4.6 of The C++ Programming Language, 2nd Edition.

## 4.2.2 Bound Pointers

Binding a pointer to a member function with a particular object as an argument to the function is not allowed in Compaq C++. For more information on the illegality of casting bound pointers, see §18.3.4 of The C++ Programming Language, 2nd Edition.

## 4.2.3 Constants in Function Returns

Because the return value cannot be an lvalue, a constant in a function return has no effect on the semantics of the return. However, using a constant in a function return does affect the type signature. For example:

    static int f1( int a, int b) {;}
    const int (* const (f2[])) (int a, int b) = {f1};

In this example, the referenced type of the pointer value `f1` in the initializer for `f2[]` is function `(signed int, signed int)` returning `signed int` . This is incompatible with function `(signed int, signed int)` returning `const signed int` .

You can omit the `const` of `int` because it affects only the constant return signature.

## 4.2.4 Pointers to Constants

The following example shows a type mismatch between a pointer to a `char` and a pointer to a `const char` that some compilers, other than the Compaq C++ compiler, may not find:

    void foo (const char* argv[]) {}
    int main()
    {
            static char* args[2] = {"foo","bar"};
    /* 'In this statement, the referenced type of the pointer value
     "args" is "pointer to char"' which is not compatible with
     "pointer to const char"'*/
            foo (args);
     return 0;
    }

You can correct this example by changing `static char` to `static const char` . Use an explicit type cast to get an argument match only if no other option is available; such a cast may break on some C++ implementations.

# 4.3 Using typedefs

Using a synonym after a `class` , `struct` , or `union` prefix is illegal. Using a synonym in the names for constructors and destructors within the class declaration itself is also illegal.

In the following example, the illegal `typedef` specifier is commented out:

    typedef struct { /* ...*/ } foo;
    // typedef struct foo foobar;             ** not legal

For more information, see §r.7.1.3 of The C++ Programming Language, 2nd Edition.

# 4.4 Initializing References

Compaq C++ warns against initializing nonconstant references to refer to temporary objects. The following example demonstrates the problems that can result:

    static void f()
    {
        int i = 5;
        i++;        // OK
        int &ri = 23;
        ri++;       // In the initializer for ri, the initialization of a
                    // non-const reference requires a temporary object for "23".
    }

The issue of reference initialization arises most often in assignment operators and in copy constructors. Wherever possible, declare all reference arguments as `const` .

For more information, see §r.8.4.3 of The C++ Programming Language, 2nd Edition.

# 4.5 Using the switch and goto Statements

Branching around a declaration with an explicit or implicit initializer is not legal, unless the declaration is in an inner block that is completely bypassed. To satisfy this constraint, enclose the declaration in a block. For example:

    int i;

    switch (i) {
    case 1:
        int l = 0;     //not initialized at this case label
        myint m = 0;   //not initialized at this case label
        {
        int j = 0;     // legal within the braces
        myint m = 0;   // legal within the braces
        }
    case 2:
        break;
    // ...
    }

For more information on using the `switch` statement, see §r.6.4.2 of The C++ Programming Language, 2nd Edition.

# 4.6 Using Volatile Objects

You must supply the meaning of copy constructing and assigning from volatile objects because the compiler generates no copy constructors or assignment operators that copy or assign from volatile objects. The following example contains examples of such errors, as noted in the comments:

    class A {
    public:
      A() { }
      // A(volatile A&) { }
      // operator=(volatile A&) { return 0; }
    };

    void foo()
    {
      volatile A va;
      A a;

      A cca(va);  // error - cannot copy construct from volatile object
      a = va;     // error - cannot assign from volatile object

      return 0;
    }

For more information, see §r.7.1.6 of The C++ Programming Language, 2nd Edition.

# 4.7 Preprocessing

Compaq C++ allows identifiers, but not expressions, on the `#ifdef` directive. For example:

    // this is not legal
    // #ifdef KERNEL && !defined(__POSIX_SOURCE)

    // use this instead
    #if defined(KERNEL) && !defined(__POSIX_SOURCE)

For more information, see §r.16.5 of The C++ Programming Language, 2nd Edition.

# 4.8 Managing Memory

The proper way to manage memory for a class is to overload the `new` and `delete` operators. This is in contrast to some older C++ implementations that let you manage memory through assignment to the `this` pointer.

For more information, see §r.5.3.3 and §r.5.3.4 of The C++ Programming Language, 2nd Edition. For information on how to avoid linker multiply defined symbol messages when redefining the global `new` and `delete` operators, see the description of the `/prefix_library_entries` qualifier in Section 1.2.1.

Make sure that user-defined `new` operators return pointers to memory that is quadword aligned.

# 4.9 Size-of-Array Argument to delete Operator

If a size-of-array argument accompanies a `delete` operator, Compaq C++ ignores the argument and issues a warning. The following example includes an anachronistic use of the `delete` operator:

    int main()
    {
            int *a = new int [20];
            int *b = new int [20];
            delete[20] a;     //old-style; argument ignored, warning issued
            delete[] b;
    return 0;
    }

# 4.10 Flushing the Output Buffer

Do not depend on the newline character (\ `n` ) to flush your terminal output buffer. If you want to flush the output buffer, use the `endl` manipulator or the `flush` member function.

# 4.11 Missing Parenthesis Error Message

Situations occur in which a simple typographical error generates a missing parenthesis error message. In the following example, the class name `CaseSensitive` is incorrectly specified as `Casesensitive` in the constructor declaration:

    class CaseSensitive {
        void Test( const Casesensitive &foo );
    };

As the compiler parses the argument declaration list, it first sees `const` , which it interprets as a type specifier. The compiler then sees `Casesensitive` , which it interprets as a `dname` . Among the next legal tokens are the equal sign, comma, and closing parenthesis. Upon finding an ampersand, the compiler expects a closing parenthesis. With all other possibilities exhausted, the compiler has what appears to be a legal argument declaration list, after which the closing parenthesis is the only allowable token. The compiler expected one thing but encountered something else. Often, inserting newline characters can isolate the offending token.

Previous | Next | Contents | Index

privacy and legal statement