The behavior of the compiler in the Cfront C++ mode is compatible with Cfront C++ V3.0, i.e. the compiler supports many of the corresponding function attributes and specific features. The Cfront C++ mode is supported so that existing code containing extensions to Cfront version V3.0 can be compiled without manual intervention. It does not guarantee full compatibility with the C++ compiler V2.2.
Consequently, note that if a program produces an error when compiled with the
C++ V2.2 compiler, it is possible that the C/C++ V4.0 compiler may produce a different error or no error at all in the Cfront C++ mode. Some of the special aspects to be noted for the Cfront C++ mode are described below.
const
qualifiers on thethis
parameter may be dropped in some contexts, as in this example:struct A { void f() const; }; void (A::*fp)() = &A::f;
This is actually a safe operation. A pointer to a function of type
const
may be put into a pointer to a non-const
type, since a call using the pointer is permitted to modify the object, and the function pointed to will actually not modify the object. An assignment in the reverse direction would not be safe.Conversion operators specifying conversion to
void
are allowed.A
friend
declaration may introduce a new type. Afriend
declaration that omits the elaborated type specifier is allowed in the C++ mode, but is also allowed to introduce a new type name in the Cfront mode.struct A { friend B; };
The third operator of the
?
operator is a conditional expression instead of an assignment expression.A reference to a pointer type may be initialized from a pointer value without using a temporary variable even if the reference pointer type has supplementary type qualifiers in addition to those present in the pointer value. For example:
int *p;
const int *&r = p; // No temporary used
A reference variable may be initialized with 0.
Since the accessibility of types is not checked in the Cfront mode, access errors for types are issued as warnings instead of errors.
When calling overloaded functions, a null pointer must be written as a string in the form "0". Other notations such as
const
variables with the value 0 or constants in the form '\0' are not interpreted as a null pointer by the compiler in the case of overloaded functions.No warning is issued when an
operator()()
function has default argument expressions.An alternate form of declaring pointer-to-member-function variables is supported. This is illustrated in the example below:
struct A { void f(int); static void sf(int); typedef void A::T3(int); // nonstd typedef decl typedef void T2(int); // std typedef }; typedef void A::T(int); // nonstd typedef decl T* pmf = &A::f; // nonstd ptr-to-member decl A::T2* pf = A::sf; // std ptr to static mem decl A::T3* pmf2 = &A::f; // nonstd ptr-to-member decl
In this example,
T
names a routine type for a nonstatic member function of classA
that takes anint
argument and returnsvoid
. The use of such types is restricted to nonstandard pointer-to-member declarations. The declarations ofT
andpmf
in combination are equivalent to a single standard pointer-to-member declaration in the form:void (A::* pmf)(int) = &A::f;
A non-standard pointer-to-member declaration that appears outside of a class declaration, such as the declaration of
T
, is normally invalid and would cause an error to be issued. For declarations that appear within a class declaration, such asA::T3
, this feature changes the meaning of a valid declaration.protected
class members are not checked when the address of a
protected
member is specified.class B { protected: inti; }; class D : public B {void mf(); }; void D::mf() { int B::* pmi1 = &B::i; // Error except in Cfront mode int D::* pmi2 = &D::i; // OK }
Note that the checking of
protected
class members for other operations (i.e. everything except the declaration of pointer-to-member addresses) is handled as defined by the standard in Cfront mode.The destructor of a derived class may implicitly call the
private
constructor of a base class.class A { ~A(); }; class B : public A { ~B(); }; B:: ~B(){} // Error except in Cfront mode
When disambiguation requires deciding whether something is a parameter declaration or an argument expression, the pattern type-name-or-keyword (identifier...) is treated as an argument. For example:
class A { A(); }; double d; A x(int(d)); A(x2);
According to the standard,
int(d)
is interpreted as a parameter declaration (with redundant parentheses), which means thatx
is a function. In the Cfront C++ mode,int(d)
is interpreted as an argument, sox
is a variable.Note that the declaration
A(x2);
is also interpreted differently in the Cfront C++ mode as compared to the standard. The standard dictates that it should be interpreted as the declaration of an object namedx2
, but in the Cfront C++ mode it is interpreted as acast
ofx2
to typeA
.A similar deviation from the standard can be seen in the interpretation of the following declaration:
int xyz(int());
According to the standard, this declares the function
xyz
, which takes a parameter that is a function without arguments and returns anint
. In the Cfront mode, this is interpreted as the declaration of an object that is initialized with the value 0.Bitfields
A named bitfield may have a size of 0. The declaration is treated as if no name were declared.
Plain bitfields, i.e. bitfields declared with the type
int
, are alwaysunsigned
.The name for a type specifier may be a
typedef
name that is a synonym for a class name:typedef class A T; class T *pa; // No error in Cfront mode
No warning is issued on duplicate size and sign (
signed
orunsigned
) type specifiers:short short int i; // No warning in Cfront mode
An extra comma is allowed after the last argument in an argument list:
f(1,2,);
A constant pointer-to-member function may be cast to a pointer-to-function. Only a warning is issued:
struct A {int f();}; main() { int (*p)(); p = (int (*)())A::f; // OK, with warning }
Arguments of class types that allow bitwise copy construction but also have destructors are passed by value (like C structures), and the destructor is not called on the “copy”. In the other modes, the class object is copied to a temporary object; the address of the temporary object is passed as the argument, and the destructor is called on the temporary object after the call returns. In practice, this is not much of a problem, since classes that allow bitwise copying usually do not have destructors.
If an unnamed class appears in a
typedef
declaration, thetypedef
name may be used as the class name.typedef struct {int i, j; } S;
struct S x; // No error in Cfront mode
A
typedef
name may be used in an explicit destructor call:struct A { ~A(); }; typedef A B; int main() { A *a; a->~B(); // Permitted in Cfront mode }
Two member functions may be declared with the same parameter types when one is static and the other is nonstatic with a function qualifier. For example:
class A { void f(int) const; static void f(int); // no error in Cfront mode }
When two functions have the same name and very similar parameter types, they cannot be used together. This is the case when the parameter types differ only in the following aspects:
char vs. signed char;
f(char);
f(signed char);
Array limits
f(char(*x)[15]);
f(char(*x)[18]);
A const qualification of a typedef
typedef char c; f(const c*); f(c*);
Indirect or combined use of these aspects
f(char*,int); f(signed char*,int); typedef char c; g(char,c*); g(signed char,const c*);
If both functions are defined nevertheless, this is interpreted as a duplicate. No message is issued during compilation.