0% found this document useful (0 votes)
133 views

Multiple Inheritance

Inheritance allows classes to reuse and extend existing classes without modifying them, creating hierarchical relationships. Inheritance lets a derived class include the members of a base class, making those members accessible through the derived class. A derived class inherits all public and protected members of the base class but not private members. Protected members of a base class can only be accessed by derived classes through a pointer, reference, or object of the derived class.

Uploaded by

Jyot Mudkanna
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
133 views

Multiple Inheritance

Inheritance allows classes to reuse and extend existing classes without modifying them, creating hierarchical relationships. Inheritance lets a derived class include the members of a base class, making those members accessible through the derived class. A derived class inherits all public and protected members of the base class but not private members. Protected members of a base class can only be accessed by derived classes through a pointer, reference, or object of the derived class.

Uploaded by

Jyot Mudkanna
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 79

Inheritance (C++ only)

Inheritance is a mechanism of reusing and extending existing classes without modifying them,
thus producing hierarchical relationships between them.

Inheritance is almost like embedding an object into a class. Suppose that you declare an object x
of class A in the class definition of B. As a result, class B will have access to all the public data
members and member functions of class A. However, in class B, you have to access the data
members and member functions of class A through object x. The following example
demonstrates this:

#include <iostream>
using namespace std;

class A {
int data;
public:
void f(int arg) { data = arg; }
int g() { return data; }
};

class B {
public:
A x;
};

int main() {
B obj;
obj.x.f(20);
cout << obj.x.g() << endl;
// cout << obj.g() << endl;
}

In the main function, object obj accesses function A::f() through its data member B::x with
the statement obj.x.f(20). Object obj accesses A::g() in a similar manner with the statement
obj.x.g(). The compiler would not allow the statement obj.g() because g() is a member
function of class A, not class B.

The inheritance mechanism lets you use a statement like obj.g() in the above example. In order
for that statement to be legal, g() must be a member function of class B.

Inheritance lets you include the names and definitions of another class's members as part of a
new class. The class whose members you want to include in your new class is called a base class.
Your new class is derived from the base class. The new class contains a subobject of the type of
the base class. The following example is the same as the previous example except it uses the
inheritance mechanism to give class B access to the members of class A:

#include <iostream>
using namespace std;

class A {
int data;
public:
void f(int arg) { data = arg; }
int g() { return data; }
};

class B : public A { };

int main() {
B obj;
obj.f(20);
cout << obj.g() << endl;
}

Class A is a base class of class B. The names and definitions of the members of class A are
included in the definition of class B; class B inherits the members of class A. Class B is derived
from class A. Class B contains a subobject of type A.

You can also add new data members and member functions to the derived class. You can modify
the implementation of existing member functions or data by overriding base class member
functions or data in the newly derived class.

You may derive classes from other derived classes, thereby creating another level of inheritance.
The following example demonstrates this:

struct A { };
struct B : A { };
struct C : B { };

Class B is a derived class of A, but is also a base class of C. The number of levels of inheritance is
only limited by resources.

Multiple inheritance allows you to create a derived class that inherits properties from more than
one base class. Because a derived class inherits members from all its base classes, ambiguities
can result. For example, if two base classes have a member with the same name, the derived
class cannot implicitly differentiate between the two members. Note that, when you are using
multiple inheritance, the access to names of base classes may be ambiguous. See Multiple
inheritance (C++ only) for more detailed information.

A direct base class is a base class that appears directly as a base specifier in the declaration of its
derived class.

An indirect base class is a base class that does not appear directly in the declaration of the
derived class but is available to the derived class through one of its base classes. For a given
class, all base classes that are not direct base classes are indirect base classes. The following
example demonstrates direct and indirect base classes:
class A {
public:
int x;
};
class B : public A {
public:
int y;
};
class C : public B { };

Class B is a direct base class of C. Class A is a direct base class of B. Class A is an indirect base
class of C. (Class C has x and y as its data members.)

Polymorphic functions are functions that can be applied to objects of more than one type. In C+
+, polymorphic functions are implemented in two ways:

 Overloaded functions are statically bound at compile time.


 C++ provides virtual functions. A virtual function is a function that can be called for a number of
different user-defined types that are related through derivation. Virtual functions are bound
dynamically at run time. They are described in more detail in Virtual functions (C++ only).

// multiple inheritance
#include <iostream>
using namespace std;

class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b;}
};

class COutput {
public:
void output (int i);
};

void COutput::output (int i) {


cout << i << endl;
}

class CRectangle: public CPolygon, public COutput {


public:
int area ()
{ return (width * height); }
};

class CTriangle: public CPolygon, public COutput {


public:
int area ()
{ return (width * height / 2); }
};

int main () {
CRectangle rect;
CTriangle trgl;
rect.set_values (4,5);
trgl.set_values (4,5);
rect.output (rect.area());
trgl.output (trgl.area());
return 0;
}

// constructors and derived classes


#include <iostream>
using namespace std;

class mother {
public:
mother ()
{ cout << "mother: no parameters\n"; }
mother (int a)
{ cout << "mother: int parameter\n"; }
};

class daughter : public mother {


public:
daughter (int a)
{ cout << "daughter: int parameter\n\n"; }
};

class son : public mother {


public:
son (int a) : mother (a)
{ cout << "son: int parameter\n\n"; }
};

int main () {
daughter cynthia (0);
son daniel(0);

return 0;
}

// friend functions
#include <iostream>
using namespace std;

class CRectangle {
int width, height;
public:
void set_values (int, int);
int area () {return (width * height);}
friend CRectangle duplicate (CRectangle);
};
void CRectangle::set_values (int a, int b) {
width = a;
height = b;
}

CRectangle duplicate (CRectangle rectparam)


{
CRectangle rectres;
rectres.width = rectparam.width*2;
rectres.height = rectparam.height*2;
return (rectres);
}

int main () {
CRectangle rect, rectb;
rect.set_values (2,3);
rectb = duplicate (rect);
cout << rectb.area();
return 0;
}

// friend class
#include <iostream>
using namespace std;

class CSquare;

class CRectangle {
int width, height;
public:
int area ()
{return (width * height);}
void convert (CSquare a);
};

class CSquare {
private:
int side;
public:
void set_side (int a)
{side=a;}
friend class CRectangle;
};

void CRectangle::convert (CSquare a) {


width = a.side;
height = a.side;
}

int main () {
CSquare sqr;
CRectangle rect;
sqr.set_side(4);
rect.convert(sqr);
cout << rect.area();
return 0;
}

Some of the exceptions to be noted in C++ inheritance are as follows.


 

 The constructor and destructor of a base class are not inherited


 the assignment operator is not inherited
 the friend functions and friend classes of the base class are also not inherited.

   There are some points to be remembered about C++ inheritance. The protected and public variables
or members of the base class are all accessible in the derived class. But a private member variable not
accessible by a derived class.

   It is a well known fact that the private and protected members are not accessible outside the class. But
a derived class is given access to protected members of the base class.

   Let us see a piece of sample code for C++ inheritance. The sample code considers a class named
vehicle with two properties to it, namely color and the number of wheels. A vehicle is a generic term and it
can later be extended to any moving vehicles like car, bike, bus etc.,

    class vehicle //Sample base class for c++ inheritance tutorial
    {
     protected:
        char colorname[20];
        int number_of_wheels;
     public:
        vehicle();
        ~vehicle();
        void start();
        void stop();
        void run();
      };
 

     class Car: public vehicle //Sample derived class for C++ inheritance tutorial
     {
       protected:
          char type_of_fuel;
       public:
          Car();
     };

   The derived class Car will have access to the protected members of the base class. It can also use the
functions start, stop and run provided the functionalities remain the same.

   In case the derived class needs some different functionalities for the same functions start, stop and run,
then the base class should implement the concept of virtual functions.

Protected members (C++ only)

A protected nonstatic base class member can be accessed by members and friends of any classes
derived from that base class by using one of the following:
 A pointer to a directly or indirectly derived class
 A reference to a directly or indirectly derived class
 An object of a directly or indirectly derived class

If a class is derived privately from a base class, all protected base class members become private
members of the derived class.

If you reference a protected nonstatic member x of a base class A in a friend or a member


function of a derived class B, you must access x through a pointer to, reference to, or object of a
class derived from A. However, if you are accessing x to create a pointer to member, you must
qualify x with a nested name specifier that names the derived class B. The following example
demonstrates this:

class A {
public:
protected:
int i;
};

class B : public A {
friend void f(A*, B*);
void g(A*);
};

void f(A* pa, B* pb) {


// pa->i = 1;
pb->i = 2;

// int A::* point_i = &A::i;


int A::* point_i2 = &B::i;
}

void B::g(A* pa) {


// pa->i = 1;
i = 2;

// int A::* point_i = &A::i;


int A::* point_i2 = &B::i;
}

void h(A* pa, B* pb) {


// pa->i = 1;
// pb->i = 2;
}

int main() { }

Class A contains one protected data member, an integer i. Because B derives from A, the
members of B have access to the protected member of A. Function f() is a friend of class B:

 The compiler would not allow pa->i = 1 because pa is not a pointer to the derived class B.
 The compiler would not allow int A::* point_i = &A::i because i has not been qualified
with the name of the derived class B.

Function g() is a member function of class B. The previous list of remarks about which
statements the compiler would and would not allow apply for g() except for the following:

 The compiler allows i = 2 because it is equivalent to this->i = 2.

Function h() cannot access any of the protected members of A because h() is neither a friend or
a member of a derived class of A.

Access control of base class members (C++ only)

When you declare a derived class, an access specifier can precede each base class in the base list
of the derived class. This does not alter the access attributes of the individual members of a base
class as seen by the base class, but allows the derived class to restrict the access control of the
members of a base class.

You can derive classes using any of the three access specifiers:

 In a public base class, public and protected members of the base class remain public and
protected members of the derived class.
 In a protected base class, public and protected members of the base class are protected
members of the derived class.
 In a private base class, public and protected members of the base class become private
members of the derived class.

In all cases, private members of the base class remain private. Private members of the base class
cannot be used by the derived class unless friend declarations within the base class explicitly
grant access to them.

In the following example, class d is derived publicly from class b. Class b is declared a public
base class by this declaration.

class b { };
class d : public b // public derivation
{ };

You can use both a structure and a class as base classes in the base list of a derived class
declaration:

 If the derived class is declared with the keyword class, the default access specifier in its base
list specifiers is private.
 If the derived class is declared with the keyword struct, the default access specifier in its base
list specifiers is public.
In the following example, private derivation is used by default because no access specifier is
used in the base list and the derived class is declared with the keyword class:

struct B
{ };
class D : B // private derivation
{ };

Members and friends of a class can implicitly convert a pointer to an object of that class to a
pointer to either:

 A direct private base class


 A protected base class (either direct or indirect)

Related information

 Member access (C++ only)


 Member scope (C++ only)

Virtual functions (C++ only)


By default, C++ matches a function call with the correct function definition at compile time. This
is called static binding. You can specify that the compiler match a function call with the correct
function definition at run time; this is called dynamic binding. You declare a function with the
keyword virtual if you want the compiler to use dynamic binding for that specific function.

The following examples demonstrate the differences between static and dynamic binding. The
first example demonstrates static binding:

#include <iostream>
using namespace std;

struct A {
void f() { cout << "Class A" << endl; }
};

struct B: A {
void f() { cout << "Class B" << endl; }
};

void g(A& arg) {


arg.f();
}

int main() {
B x;
g(x);
}
The following is the output of the above example:

Class A

When function g() is called, function A::f() is called, although the argument refers to an object
of type B. At compile time, the compiler knows only that the argument of function g() will be a
reference to an object derived from A; it cannot determine whether the argument will be a
reference to an object of type A or type B. However, this can be determined at run time. The
following example is the same as the previous example, except that A::f() is declared with the
virtual keyword:

#include <iostream>
using namespace std;

struct A {
virtual void f() { cout << "Class A" << endl; }
};

struct B: A {
void f() { cout << "Class B" << endl; }
};

void g(A& arg) {


arg.f();
}

int main() {
B x;
g(x);
}

The following is the output of the above example:

Class B

The virtual keyword indicates to the compiler that it should choose the appropriate definition
of f() not by the type of reference, but by the type of object that the reference refers to.

Therefore, a virtual function is a member function you may redefine for other derived classes,
and can ensure that the compiler will call the redefined virtual function for an object of the
corresponding derived class, even if you call that function with a pointer or reference to a base
class of the object.

A class that declares or inherits a virtual function is called a polymorphic class.

You redefine a virtual member function, like any member function, in any derived class.
Suppose you declare a virtual function named f in a class A, and you derive directly or indirectly
from A a class named B. If you declare a function named f in class B with the same name and
same parameter list as A::f, then B::f is also virtual (regardless whether or not you declare
B::f with the virtual keyword) and it overrides A::f. However, if the parameter lists of A::f
and B::f are different, A::f and B::f are considered different, B::f does not override A::f, and
B::f is not virtual (unless you have declared it with the virtual keyword). Instead B::f hides
A::f. The following example demonstrates this:

#include <iostream>
using namespace std;

struct A {
virtual void f() { cout << "Class A" << endl; }
};

struct B: A {
void f(int) { cout << "Class B" << endl; }
};

struct C: B {
void f() { cout << "Class C" << endl; }
};

int main() {
B b; C c;
A* pa1 = &b;
A* pa2 = &c;
// b.f();
pa1->f();
pa2->f();
}

The following is the output of the above example:

Class A
Class C

The function B::f is not virtual. It hides A::f. Thus the compiler will not allow the function call
b.f(). The function C::f is virtual; it overrides A::f even though A::f is not visible in C.

If you declare a base class destructor as virtual, a derived class destructor will override that base
class destructor, even though destructors are not inherited.

The return type of an overriding virtual function may differ from the return type of the
overridden virtual function. This overriding function would then be called a covariant virtual
function. Suppose that B::f overrides the virtual function A::f. The return types of A::f and
B::f may differ if all the following conditions are met:

 The function B::f returns a reference or pointer to a class of type T, and A::f returns a
pointer or a reference to an unambiguous direct or indirect base class of T.
 The const or volatile qualification of the pointer or reference returned by B::f has the
same or less const or volatile qualification of the pointer or reference returned by A::f.
 The return type of B::f must be complete at the point of declaration of B::f, or it can be
of type B.
The following example demonstrates this:

#include <iostream>
using namespace std;

struct A { };

class B : private A {
friend class D;
friend class F;
};

A global_A;
B global_B;

struct C {
virtual A* f() {
cout << "A* C::f()" << endl;
return &global_A;
}
};

struct D : C {
B* f() {
cout << "B* D::f()" << endl;
return &global_B;
}
};

struct E;

struct F : C {

// Error:
// E is incomplete
// E* f();
};

struct G : C {

// Error:
// A is an inaccessible base class of B
// B* f();
};

int main() {
D d;
C* cp = &d;
D* dp = &d;

A* ap = cp->f();
B* bp = dp->f();
};

The following is the output of the above example:


B* D::f()
B* D::f()

The statement A* ap = cp->f() calls D::f() and converts the pointer returned to type A*. The
statement B* bp = dp->f() calls D::f() as well but does not convert the pointer returned; the
type returned is B*. The compiler would not allow the declaration of the virtual function F::f()
because E is not a complete class. The compiler would not allow the declaration of the virtual
function G::f() because class A is not an accessible base class of B (unlike friend classes D and
F, the definition of B does not give access to its members for class G).

A virtual function cannot be global or static because, by definition, a virtual function is a


member function of a base class and relies on a specific object to determine which
implementation of the function is called. You can declare a virtual function to be a friend of
another class.

If a function is declared virtual in its base class, you can still access it directly using the scope
resolution (::) operator. In this case, the virtual function call mechanism is suppressed and the
function implementation defined in the base class is used. In addition, if you do not override a
virtual member function in a derived class, a call to that function uses the function
implementation defined in the base class.

A virtual function must be one of the following:

 Defined
 Declared pure
 Defined and declared pure

A base class containing one or more pure virtual member functions is called an abstract class.

Related information

Abstract classes (C++ only)


An abstract class is a class that is designed to be specifically used as a base class. An abstract
class contains at least one pure virtual function. You declare a pure virtual function by using a
pure specifier (= 0) in the declaration of a virtual member function in the class declaration.

The following is an example of an abstract class:

class AB {
public:
virtual void f() = 0;
};

Function AB::f is a pure virtual function. A function declaration cannot have both a pure
specifier and a definition. For example, the compiler will not allow the following:
struct A {
virtual void g() { } = 0;
};

You cannot use an abstract class as a parameter type, a function return type, or the type of an
explicit conversion, nor can you declare an object of an abstract class. You can, however, declare
pointers and references to an abstract class. The following example demonstrates this:

struct A {
virtual void f() = 0;
};

struct B : A {
virtual void f() { }
};

// Error:
// Class A is an abstract class
// A g();

// Error:
// Class A is an abstract class
// void h(A);
A& i(A&);

int main() {

// Error:
// Class A is an abstract class
// A a;

A* pa;
B b;

// Error:
// Class A is an abstract class
// static_cast<A>(b);
}

Class A is an abstract class. The compiler would not allow the function declarations A g() or
void h(A), declaration of object a, nor the static cast of b to type A.

Virtual member functions are inherited. A class derived from an abstract base class will also be
abstract unless you override each pure virtual function in the derived class.

For example:

class AB {
public:
virtual void f() = 0;
};

class D2 : public AB {
void g();
};

int main() {
D2 d;
}

The compiler will not allow the declaration of object d because D2 is an abstract class; it
inherited the pure virtual function f()from AB. The compiler will allow the declaration of object
d if you define function D2::g().

Note that you can derive an abstract class from a nonabstract class, and you can override a non-
pure virtual function with a pure virtual function.

You can call member functions from a constructor or destructor of an abstract class. However,
the results of calling (directly or indirectly) a pure virtual function from its constructor are
undefined. The following example demonstrates this:

struct A {
A() {
direct();
indirect();
}
virtual void direct() = 0;
virtual void indirect() { direct(); }
};

The default constructor of A calls the pure virtual function direct() both directly and indirectly
(through indirect()).

The compiler issues a warning for the direct call to the pure virtual function, but not for the
indirect call.

Virtual function access (C++ only)

The access for a virtual function is specified when it is declared. The access rules for a virtual
function are not affected by the access rules for the function that later overrides the virtual
function. In general, the access of the overriding member function is not known.

If a virtual function is called with a pointer or reference to a class object, the type of the class
object is not used to determine the access of the virtual function. Instead, the type of the pointer
or reference to the class object is used.

In the following example, when the function f() is called using a pointer having type B*, bptr is
used to determine the access to the function f(). Although the definition of f() defined in class
D is executed, the access of the member function f() in class B is used. When the function f() is
called using a pointer having type D*, dptr is used to determine the access to the function f().
This call produces an error because f() is declared private in class D.
class B {
public:
virtual void f();
};

class D : public B {
private:
void f();
};

int main() {
D dobj;
B* bptr = &dobj;
D* dptr = &dobj;

// valid, virtual B::f() is public,


// D::f() is called
bptr->f();

// error, D::f() is private


dptr->f();
}

Templates (C++ only)

A template describes a set of related classes or set of related functions in which a list of
parameters in the declaration describe how the members of the set vary. The compiler generates
new classes or functions when you supply arguments for these parameters; this process is called
template instantiation, and is described in detail in Template instantiation (C++ only). This class
or function definition generated from a template and a set of template parameters is called a
specialization, as described in Template specialization (C++ only).

Template declaration syntax

>>-+--------+--------------------------------------------------->
'-export-'

>--template--<--template_parameter_list-->--declaration--------><

The compiler accepts and silently ignores the export keyword on a template.

The template_parameter_list is a comma-separated list of template parameters, which are


described in Template parameters (C++ only).

The declaration is one of the following::

 a declaration or definition of a function or a class


 a definition of a member function or a member class of a class template
 a definition of a static data member of a class template
 a definition of a static data member of a class nested within a class template
 a definition of a member template of a class or class template

The identifier of a type is defined to be a type_name in the scope of the template declaration. A
template declaration can appear as a namespace scope or class scope declaration.

The following example demonstrates the use of a class template:

template<class T> class Key


{
T k;
T* kptr;
int length;
public:
Key(T);
// ...
};

Suppose the following declarations appear later:

Key<int> i;
Key<char*> c;
Key<mytype> m;

The compiler would create three instances of class Key. The following table shows the
definitions of these three class instances if they were written out in source form as regular
classes, not as templates:

class Key<int> i; class Key<char*> c; class Key<mytype> m;


class Key class Key class Key
{ { {
int k; char* k; mytype k;
int * kptr; char** kptr; mytype* kptr;
int length; int length; int length;
public: public: public:
Key(int); Key(char*); Key(mytype);
// ... // ... // ...
}; }; };
Note that these three classes have different names. The arguments contained within the angle
braces are not just the arguments to the class names, but part of the class names themselves.
Key<int> and Key<char*> are class names.

Template instantiation (C++ only)


The act of creating a new definition of a function, class, or member of a class from a template
declaration and one or more template arguments is called template instantiation. The definition
created from a template instantiation to handle a specific set of template arguments is called a
specialization.

IBM extension

A forward declaration of a template instantiation has the form of an explicit template


instantiation preceded by the extern keyword.

End of IBM extension

Template instantiation declaration syntax

>>-extern--template--template_declaration----------------------><

The language feature is an orthogonal extension to Standard C++ for compatibility with GNU
C++, and is described further in Explicit instantiation (C++ only).

Explicit instantiation (C++ only)

You can explicitly tell the compiler when it should generate a definition from a template. This is
called explicit instantiation.

Explicit instantiation declaration syntax

>>-template--template_declaration------------------------------><

The following are examples of explicit instantiations:

template<class T> class Array { void mf(); };


template class Array<char>; // explicit instantiation
template void Array<int>::mf(); // explicit instantiation

template<class T> void sort(Array<T>& v) { }


template void sort(Array<char>&); // explicit instantiation

namespace N {
template<class T> void f(T&) { }
}

template void N::f<int>(int&);


// The explicit instantiation is in namespace N.

int* p = 0;
template<class T> T g(T = &p);
template char g(char); // explicit instantiation

template <class T> class X {


private:
T v(T arg) { return arg; };
};
template int X<int>::v(int); // explicit instantiation

template<class T> T g(T val) { return val;}


template<class T> void Array<T>::mf() { }

A template declaration must be in scope at the point of instantiation of the template's explicit
instantiation. An explicit instantiation of a template specialization is in the same namespace
where you defined the template.

Access checking rules do not apply to names in explicit instantiations. Template arguments and
names in a declaration of an explicit instantiation may be private types or objects. In the above
example, the compiler allows the explicit instantiation template int X<int>::v(int) even
though the member function is declared private.

The compiler does not use default arguments when you explicitly instantiate a template. In the
above example the compiler allows the explicit instantiation template char g(char) even
though the default argument is an address of type int.

IBM extension

An extern-qualified template declaration does not instantiate the class or function. For both
classes and functions, the extern template instantiation prevents the instantiation of parts of the
template, provided that the instantiation has not already been triggered by code prior to the
extern template instantiation. For classes, the members (both static and nonstatic) are not
instantiated. The class itself is instantiated if required to map the class. For functions, the
prototype is instantiated, but the body of the template function is not instantiated.

The following examples show template instantiation using extern:

template<class T>class C {
static int i;
void f(T) { }
};
template<class U>int C<U>::i = 0;
extern template C<int>; // extern explicit template instantiation
C<int>c; // does not cause instantiation of C<int>::i
// or C<int>::f(int) in this file,
// but the class is instantiated for mapping
C<char>d; // normal instantiations
template<class C> C foo(C c) { return c; }
extern template int foo<int>(int); // extern explicit template instantiation
int i = foo(1); // does not cause instantiation of the body of foo<int>
End of IBM extension

Template specialization (C++ only)


The act of creating a new definition of a function, class, or member of a class from a template
declaration and one or more template arguments is called template instantiation. The definition
created from a template instantiation is called a specialization. A primary template is the
template that is being specialized.

Member access (C++ only)


Member access determines if a class member is accessible in an expression or declaration.
Suppose x is a member of class A. Class member x can be declared to have one of the following
levels of accessibility:

 public: x can be used anywhere without the access restrictions defined by private or
protected.
 private: x can be used only by the members and friends of class A.
 protected: x can be used only by the members and friends of class A, and the members
and friends of classes derived from class A.

Members of classes declared with the keyword class are private by default. Members of classes
declared with the keyword struct or union are public by default.

To control the access of a class member, you use one of the access specifiers public, private,
or protected as a label in a class member list. The following example demonstrates these access
specifiers:

struct A {
friend class C;
private:
int a;
public:
int b;
protected:
int c;
};

struct B : A {
void f() {
// a = 1;
b = 2;
c = 3;
}
};

struct C {
void f(A x) {
x.a = 4;
x.b = 5;
x.c = 6;
}
};
int main() {
A y;
// y.a = 7;
y.b = 8;
// y.c = 9;

B z;
// z.a = 10;
z.b = 11;
// z.c = 12;
}

The following table lists the access of data members A::a A::b, and A::c in various scopes of
the above example.

Scope A::a A::b A::c

function No access. Member A::a Access. Member A::b Access. Class B inherits
B::f() is private. is public. from A.
function Access. Class C is a friend Access. Member A::b Access. Class C is a friend
C::f() of A. is public. of A.
object y in No access. Member y.a is Access. Member y.a is No access. Member y.c is
main() private. public. protected.
object z in No access. Member z.a is Access. Member z.a is No access. Member z.c is
main() private. public. protected.

An access specifier specifies the accessibility of members that follow it until the next access
specifier or until the end of the class definition. You can use any number of access specifiers in
any order. If you later define a class member within its class definition, its access specification
must be the same as its declaration. The following example demonstrates this:

class A {
class B;
public:
class B { };
};

The compiler will not allow the definition of class B because this class has already been declared
as private.

A class member has the same access control regardless whether it has been defined within its
class or outside its class.

Access control applies to names. In particular, if you add access control to a typedef name, it
affects only the typedef name. The following example demonstrates this:

class A {
class B { };
public:
typedef B C;
};

int main() {
A::C x;
// A::B y;
}

The compiler will allow the declaration A::C x because the typedef name A::C is public. The
compiler would not allow the declaration A::B y because A::B is private.

Note that accessibility and visibility are independent. Visibility is based on the scoping rules of
C++. A class member can be visible and inaccessible at the same time.

Exception handling (C++ only)

Exception handling is a mechanism that separates code that detects and handles exceptional
circumstances from the rest of your program. Note that an exceptional circumstance is not
necessarily an error.

When a function detects an exceptional situation, you represent this with an object. This object is
called an exception object. In order to deal with the exceptional situation you throw the
exception. This passes control, as well as the exception, to a designated block of code in a direct
or indirect caller of the function that threw the exception. This block of code is called a handler.
In a handler, you specify the types of exceptions that it may process. The C++ run time, together
with the generated code, will pass control to the first appropriate handler that is able to process
the exception thrown. When this happens, an exception is caught. A handler may rethrow an
exception so it can be caught by another handler.

The exception handling mechanism is made up of the following elements:

 try blocks
 catch blocks
 throw expressions
 Exception specifications (C++ only)

try blocks (C++ only)


You use a try block to indicate which areas in your program that might throw exceptions you
want to handle immediately. You use a function try block to indicate that you want to detect
exceptions in the entire body of a function.

try block syntax

.---------.
V |
>>-try--{--statements--}----handler-+--------------------------><

Function try block syntax

.---------.
V |
>>-try--+----------------------------+--function_body----handler-+-><
'-:--member_initializer_list-'

The following is an example of a function try block with a member initializer, a function try
block and a try block:

#include <iostream>
using namespace std;

class E {
public:
const char* error;
E(const char* arg) : error(arg) { }
};

class A {
public:
int i;

// A function try block with a member


// initializer
A() try : i(0) {
throw E("Exception thrown in A()");
}
catch (E& e) {
cout << e.error << endl;
}
};

// A function try block


void f() try {
throw E("Exception thrown in f()");
}
catch (E& e) {
cout << e.error << endl;
}

void g() {
throw E("Exception thrown in g()");
}

int main() {
f();

// A try block
try {
g();
}
catch (E& e) {
cout << e.error << endl;
}
try {
A x;
}
catch(...) { }
}

The following is the output of the above example:

Exception thrown in f()


Exception thrown in g()
Exception thrown in A()

The constructor of class A has a function try block with a member initializer. Function f() has a
function try block. The main() function contains a try block.

Related information

 Initializing base classes and members (C++ only)

catch blocks (C++ only)


catch block syntax

>>-catch--(--exception_declaration--)--{--statements--}--------><

You can declare a handler to catch many types of exceptions. The allowable objects that a
function can catch are declared in the parentheses following the catch keyword (the
exception_declaration). You can catch objects of the fundamental types, base and derived class
objects, references, and pointers to all of these types. You can also catch const and volatile
types. The exception_declaration cannot be an incomplete type, or a reference or pointer to an
incomplete type other than one of the following:

 void*
 const void*
 volatile void*
 const volatile void*
You cannot define a type in an exception_declaration.

You can also use the catch(...) form of the handler to catch all thrown exceptions that have
not been caught by a previous catch block. The ellipsis in the catch argument indicates that any
exception thrown can be handled by this handler.

If an exception is caught by a catch(...) block, there is no direct way to access the object
thrown. Information about an exception caught by catch(...) is very limited.

You can declare an optional variable name if you want to access the thrown object in the catch
block.

A catch block can only catch accessible objects. The object caught must have an accessible copy
constructor.

throw expressions (C++ only)


You use a throw expression to indicate that your program has encountered an exception.

throw expression syntax

>>-throw--+-----------------------+----------------------------><
'-assignment_expression-'

The type of assignment_expression cannot be an incomplete type, or a pointer to an incomplete


type other than one of the following:

 void*
 const void*
 volatile void*
 const volatile void*

The assignment_expression is treated the same way as a function argument in a call or the
operand of a return statement.

If the assignment_expression is a class object, the copy constructor and destructor of that object
must be accessible. For example, you cannot throw a class object that has its copy constructor
declared as private.

Exception specifications (C++ only)


C++ provides a mechanism to ensure that a given function is limited to throwing only a specified
list of exceptions. An exception specification at the beginning of any function acts as a guarantee
to the function's caller that the function will throw only the exceptions contained in the exception
specification.

For example, a function:

void translate() throw(unknown_word,bad_grammar) { /* ... */ }

explicitly states that it will only throw exception objects whose types are unknown_word or
bad_grammar, or any type derived from unknown_word or bad_grammar.

Exception specification syntax

>>-throw--(--+--------------+--)-------------------------------><
'-type_id_list-'

The type_id_list is a comma-separated list of types. In this list you cannot specify an incomplete
type, a pointer or a reference to an incomplete type, other than a pointer to void, optionally
qualified with const and/or volatile. You cannot define a type in an exception specification.

A function with no exception specification allows all exceptions. A function with an exception
specification that has an empty type_id_list, throw(), does not allow any exceptions to be
thrown.

An exception specification is not part of a function's type.

An exception specification may only appear at the end of a function declarator of a function,
pointer to function, reference to function, pointer to member function declaration, or pointer to
member function definition. An exception specification cannot appear in a typedef declaration.
The following declarations demonstrate this:

void f() throw(int);


void (*g)() throw(int);
void h(void i() throw(int));
// typedef int (*j)() throw(int); This is an error.

The compiler would not allow the last declaration, typedef int (*j)() throw(int).

Suppose that class A is one of the types in the type_id_list of an exception specification of a
function. That function may throw exception objects of class A, or any class publicly derived
from class A. The following example demonstrates this:

class A { };
class B : public A { };
class C { };

void f(int i) throw (A) {


switch (i) {
case 0: throw A();
case 1: throw B();
default: throw C();
}
}

void g(int i) throw (A*) {


A* a = new A();
B* b = new B();
C* c = new C();
switch (i) {
case 0: throw a;
case 1: throw b;
default: throw c;
}
}

Function f() can throw objects of types A or B. If the function tries to throw an object of type C,
the compiler will call unexpected() because type C has not been specified in the function's
exception specification, nor does it derive publicly from A. Similarly, function g() cannot throw
pointers to objects of type C; the function may throw pointers of type A or pointers of objects that
derive publicly from A.

A function that overrides a virtual function can only throw exceptions specified by the virtual
function. The following example demonstrates this:

class A {
public:
virtual void f() throw (int, char);
};

class B : public A{
public: void f() throw (int) { }
};

/* The following is not allowed. */


/*
class C : public A {
public: void f() { }
};

class D : public A {
public: void f() throw (int, char, double) { }
};
*/

The compiler allows B::f() because the member function may throw only exceptions of type
int. The compiler would not allow C::f() because the member function may throw any kind of
exception. The compiler would not allow D::f() because the member function can throw more
types of exceptions (int, char, and double) than A::f().
Suppose that you assign or initialize a pointer to function named x with a function or pointer to
function named y. The pointer to function x can only throw exceptions specified by the exception
specifications of y. The following example demonstrates this:

void (*f)();
void (*g)();
void (*h)() throw (int);

void i() {
f = h;
// h = g; This is an error.
}

The compiler allows the assignment f = h because f can throw any kind of exception. The
compiler would not allow the assignment h = g because h can only throw objects of type int,
while g can throw any kind of exception.

Implicitly declared special member functions (default constructors, copy constructors,


destructors, and copy assignment operators) have exception specifications. An implicitly
declared special member function will have in its exception specification the types declared in
the functions' exception specifications that the special function invokes. If any function that a
special function invokes allows all exceptions, then that special function allows all exceptions. If
all the functions that a special function invokes allow no exceptions, then that special function
will allow no exceptions. The following example demonstrates this:

class A {
public:
A() throw (int);
A(const A&) throw (float);
~A() throw();
};

class B {
public:
B() throw (char);
B(const A&);
~B() throw();
};

class C : public B, public A { };

The following special functions in the above example have been implicitly declared:

C::C() throw (int, char);


C::C(const C&); // Can throw any type of exception, including float
C::~C() throw();

The default constructor of C can throw exceptions of type int or char. The copy constructor of C
can throw any kind of exception. The destructor of C cannot throw any exceptions.
Preprocessor Directives

The preprocessor is a program that is invoked by the compiler to process code before
compilation. Commands for that program, known as directives, are lines of the source file
beginning with the character #, which distinguishes them from lines of source program text. The
effect of each preprocessor directive is a change to the text of the source code, and the result is a
new source code file, which does not contain the directives. The preprocessed source code, an
intermediate file, must be a valid C or C++ program, because it becomes the input to the
compiler.

Preprocessor directives consist of the following:

 Macro definition directives, which replace tokens in the current file with specified replacement
tokens
 File inclusion directives, which imbed files within the current file
 Conditional compilation directives, which conditionally compile sections of the current file
 Message generation directives, which control the generation of diagnostic messages
 Assertion directives, which specify attributes of the system the program is to run on
 The null directive (#), which performs no action
 Pragma directives, which apply compiler-specific rules to specified sections of code

Preprocessor directives begin with the # token followed by a preprocessor keyword. The # token
must appear as the first character that is not white space on a line. The # is not part of the
directive name and can be separated from the name with white spaces.

A preprocessor directive ends at the new-line character unless the last character of the line is the
\ (backslash) character. If the \ character appears as the last character in the preprocessor line,
the preprocessor interprets the \ and the new-line character as a continuation marker. The
preprocessor deletes the \ (and the following new-line character) and splices the physical source
lines into continuous logical lines. White space is allowed between backslash and the end of line
character or the physical end of record. However, this white space is usually not visible during
editing.

Except for some #pragma directives, preprocessor directives can appear anywhere in a program.

Macro definition directives


Macro definition directives include the following directives and operators:

 The #define directive, which defines a macro

The #define directive

A preprocessor define directive directs the preprocessor to replace all subsequent occurrences of
a macro with specified replacement tokens.
#define directive syntax

>>-#--define--identifier--+--------------------------+---------->
| .-,--------------. |
| V | |
'-(----+------------+-+--)-'
'-identifier-'

.----------------.
V |
>----+------------+-+------------------------------------------><
+-identifier-+
'-character--'

The #define directive can contain:

 Object-like macros
 Function-like macros

The following are some differences between #define and the const type qualifier:

 The #define directive can be used to create a name for a numerical, character, or string
constant, whereas a const object of any type can be declared.
 A const object is subject to the scoping rules for variables, whereas a constant created using
#define is not.
 Unlike a const object, the value of a macro does not appear in the intermediate source code
used by the compiler because they are expanded inline. The inline expansion makes the macro
value unavailable to the debugger.
 A macro can be used in a constant expression, such as an array bound, whereas a const object
cannot.
 The compiler does not type-check a macro, including macro arguments.

Related information

 The const type qualifier

Object-like macros

An object-like macro definition replaces a single identifier with the specified replacement
tokens. The following object-like definition causes the preprocessor to replace all subsequent
instances of the identifier COUNT with the constant 1000 :

#define COUNT 1000

If the statement

int arry[COUNT];
appears after this definition and in the same file as the definition, the preprocessor would change
the statement to

int arry[1000];

in the output of the preprocessor.

Other definitions can make reference to the identifier COUNT:

#define MAX_COUNT COUNT + 100

The preprocessor replaces each subsequent occurrence of MAX_COUNT with COUNT + 100, which
the preprocessor then replaces with 1000 + 100.

If a number that is partially built by a macro expansion is produced, the preprocessor does not
consider the result to be a single value. For example, the following will not result in the value
10.2 but in a syntax error.

#define a 10
a.2

Identifiers that are partially built from a macro expansion may not be produced. Therefore, the
following example contains two identifiers and results in a syntax error:

#define d efg
abcd

Function-like macros

More complex than object-like macros, a function-like macro definition declares the names of
formal parameters within parentheses, separated by commas. An empty formal parameter list is
legal: such a macro can be used to simulate a function that takes no arguments. C99 adds support
for function-like macros with a variable number of arguments. XL C++ supports function-like
macros with a variable number of arguments, as a language extension for compatibility with C.

Function-like macro definition:

An identifier followed by a parameter list in parentheses and the replacement tokens. The
parameters are imbedded in the replacement code. White space cannot separate the identifier
(which is the name of the macro) and the left parenthesis of the parameter list. A comma must
separate each parameter.

For portability, you should not have more than 31 parameters for a macro. The parameter
list may end with an ellipsis (...). In this case, the identifier __VA_ARGS__ may appear in
the replacement list.

Function-like macro invocation:


An identifier followed by a comma-separated list of arguments in parentheses. The number of
arguments should match the number of parameters in the macro definition, unless the
parameter list in the definition ends with an ellipsis. In this latter case, the number of arguments
in the invocation should exceed the number of parameters in the definition. The excess are
called trailing arguments. Once the preprocessor identifies a function-like macro invocation,
argument substitution takes place. A parameter in the replacement code is replaced by the
corresponding argument. If trailing arguments are permitted by the macro definition, they are
merged with the intervening commas to replace the identifier __VA_ARGS__, as if they were a
single argument. Any macro invocations contained in the argument itself are completely
replaced before the argument replaces its corresponding parameter in the replacement code.

A macro argument can be empty (consisting of zero preprocessing tokens). For example,

#define SUM(a,b,c) a + b + c
SUM(1,,3) /* No error message.
1 is substituted for a, 3 is substituted for c. */

If the identifier list does not end with an ellipsis, the number of arguments in a macro invocation
must be the same as the number of parameters in the corresponding macro definition. During
parameter substitution, any arguments remaining after all specified arguments have been
substituted (including any separating commas) are combined into one argument called the
variable argument. The variable argument will replace any occurrence of the identifier
__VA_ARGS__ in the replacement list. The following example illustrates this:

#define debug(...) fprintf(stderr, __VA_ARGS__)

debug("flag"); /* Becomes fprintf(stderr, "flag"); */

Commas in the macro invocation argument list do not act as argument separators when they are:

 In character constants
 In string literals
 Surrounded by parentheses

The following line defines the macro SUM as having two parameters a and b and the replacement
tokens (a + b):

#define SUM(a,b) (a + b)

This definition would cause the preprocessor to change the following statements (if the
statements appear after the previous definition):

c = SUM(x,y);
c = d * SUM(x,y);

In the output of the preprocessor, these statements would appear as:


c = (x + y);
c = d * (x + y);

Use parentheses to ensure correct evaluation of replacement text. For example, the definition:

#define SQR(c) ((c) * (c))

requires parentheses around each parameter c in the definition in order to correctly evaluate an
expression like:

y = SQR(a + b);

The preprocessor expands this statement to:

y = ((a + b) * (a + b));

Without parentheses in the definition, the correct order of evaluation is not preserved, and the
preprocessor output is:

y = (a + b * a + b);

Arguments of the # and ## operators are converted before replacement of parameters in a


function-like macro.

Once defined, a preprocessor identifier remains defined and in scope independent of the scoping
rules of the language. The scope of a macro definition begins at the definition and does not end
until a corresponding #undef directive is encountered. If there is no corresponding #undef
directive, the scope of the macro definition lasts until the end of the translation unit.

A recursive macro is not fully expanded. For example, the definition

#define x(a,b) x(a+1,b+1) + 4

expands

x(20,10)

to

x(20+1,10+1) + 4

rather than trying to expand the macro x over and over within itself. After the macro x is
expanded, it is a call to function x().

A definition is not required to specify replacement tokens. The following definition removes all
instances of the token debug from subsequent lines in the current file:

#define debug
You can change the definition of a defined identifier or macro with a second preprocessor
#define directive only if the second preprocessor #define directive is preceded by a
preprocessor #undef directive. The #undef directive nullifies the first definition so that the same
identifier can be used in a redefinition.

Within the text of the program, the preprocessor does not scan character constants or string
constants for macro invocations.

The following example program contains two macro definitions and a macro invocation that
refers to both of the defined macros:

/**
** This example illustrates #define directives.
**/

#include <stdio.h>

#define SQR(s) ((s) * (s))


#define PRNT(a,b) \
printf("value 1 = %d\n", a); \
printf("value 2 = %d\n", b) ;

int main(void)
{
int x = 2;
int y = 3;

PRNT(SQR(x),y);

return(0);
}

After being interpreted by the preprocessor, this program is replaced by code equivalent to the
following:

#include <stdio.h>

int main(void)
{
int x = 2;
int y = 3;

printf("value 1 = %d\n", ( (x) * (x) ) );


printf("value 2 = %d\n", y);

return(0);
}

This program produces the following output:

value 1 = 4
value 2 = 3
Related information

 Operator precedence and associativity


 Parenthesized expressions ( )

IBM extension

Variadic macro extensions

Variadic macro extensions refer to two extensions to C99 and Standard C++ related to macros
with variable number of arguments. One extension is a mechanism for renaming the variable
argument identifier from __VA_ARGS__ to a user-defined identifier. The other extension provides
a way to remove the dangling comma in a variadic macro when no variable arguments are
specified. Both extensions have been implemented to facilitate porting programs developed with
GNU C and C++.

The following examples demonstrate the use of an identifier in place of __VA_ARGS__. The first
definition of the macro debug exemplifies the usual usage of __VA_ARGS__. The second
definition shows the use of the identifier args in place of __VA_ARGS__.

#define debug1(format, ...) printf(format, __VA_ARGS__)


#define debug2(format, args ...) printf(format, args)
Invocation Result of Macro Expansion

debug1("Hello %s\n","World"); printf("Hello %s\n","World");

debug2("Hello %s\n","World"); printf("Hello %s\n","World");

The preprocessor removes the trailing comma if the variable arguments to a function macro are
omitted or empty and the comma followed by ## precedes the variable argument identifier in the
function macro definition.



 The #undef directive, which removes a macro definition

The #undef directive

A preprocessor undef directive causes the preprocessor to end the scope of a preprocessor
definition.

#undef directive syntax

>>-#--undef--identifier----------------------------------------><

If the identifier is not currently defined as a macro, #undef is ignored.


The following directives define BUFFER and SQR:

#define BUFFER 512


#define SQR(x) ((x) * (x))

The following directives nullify these definitions:

#undef BUFFER
#undef SQR

Any occurrences of the identifiers BUFFER and SQR that follow these #undef directives are not
replaced with any replacement tokens. Once the definition of a macro has been removed by an
#undef directive, the identifier can be used in a new #define directive.

Standard predefined macro names describes the macros that are predefined by the ISO C
standard. Macros that are predefined for XL C/C++ are described in "Predefined
macros" .

File inclusion directives


File inclusion directives consist of:

 The #include directive, which inserts text from another source file
 The #include_next directive

The #include directive

A preprocessor include directive causes the preprocessor to replace the directive with the
contents of the specified file.

#include directive syntax

>>-#--include--+-"--file_name--"---+---------------------------><
+-<--file_name-->---+
+-<--header_name-->-+
'-identifiers-------'

In all C and C++ implementations, the preprocessor resolves macros contained in an #include
directive. After macro replacement, the resulting token sequence must consist of a file name
enclosed in either double quotation marks or the characters < and >.

For example:
#define MONTH <july.h>
#include MONTH

If the file name is enclosed in double quotation marks, for example:

#include "payroll.h"

the preprocessor treats it as a user-defined file, and searches for the file in a manner defined by
the preprocessor.

If the file name is enclosed in angle brackets, for example:

#include <stdio.h>

it is treated as a system-defined file, and the preprocessor searches for the file in a manner
defined by the preprocessor.

The new-line and > characters cannot appear in a file name delimited by < and >. The new-line
and " (double quotation marks) character cannot appear in a file name delimited by " and ",
although > can.

Declarations that are used by several files can be placed in one file and included with #include
in each file that uses them. For example, the following file defs.h contains several definitions
and an inclusion of an additional file of declarations:

/* defs.h */
#define TRUE 1
#define FALSE 0
#define BUFFERSIZE 512
#define MAX_ROW 66
#define MAX_COLUMN 80
int hour;
int min;
int sec;
#include "mydefs.h"

You can embed the definitions that appear in defs.h with the following directive:

#include "defs.h"

In the following example, a #define combines several preprocessor macros to define a macro
that represents the name of the C standard I/O header file. A #include makes the header file
available to the program.

#define C_IO_HEADER <stdio.h>

/* The following is equivalent to:


* #include <stdio.h>
*/
#include C_IO_HEADER

Conditional compilation directives


A preprocessor conditional compilation directive causes the preprocessor to conditionally
suppress the compilation of portions of source code. These directives test a constant expression
or an identifier to determine which tokens the preprocessor should pass on to the compiler and
which tokens should be bypassed during preprocessing. The directives are:

 The #if and #elif directives, which conditionally include or suppress portions of source
code, depending on the result of a constant expression

The #if and #elif directives

The #if and #elif directives compare the value of constant_expression to zero:

#if and #elif directive syntax

.----------------.
V |
>>-#--+-if---+--constant_expression----token_sequence-+--------><
'-elif-'

If the constant expression evaluates to a nonzero value, the lines of code that immediately follow
the condition are passed on to the compiler.

If the expression evaluates to zero and the conditional compilation directive contains a
preprocessor #elif directive, the source text located between the #elif and the next #elif or
preprocessor #else directive is selected by the preprocessor to be passed on to the compiler. The
#elif directive cannot appear after the preprocessor #else directive.

All macros are expanded, any defined() expressions are processed and all remaining identifiers
are replaced with the token 0.

The constant_expression that is tested must be integer constant expressions with the following
properties:

 No casts are performed.


 Arithmetic is performed using long int values.
 The constant_expression can contain defined macros. No other identifiers can appear in the
expression.
 The constant_expression can contain the unary operator defined. This operator can be used
only with the preprocessor keyword #if or #elif. The following expressions evaluate to 1 if
the identifier is defined in the preprocessor, otherwise to 0:
 defined identifier
defined(identifier)
For example:

#if defined(TEST1) || defined(TEST2)


Note:

If a macro is not defined, a value of 0 (zero) is assigned to it. In the following example, TEST must be a
macro identifier:

#if TEST >= 1


printf("i = %d\n", i);
printf("array[i] = %d\n", array[i]);
#elif TEST < 0
printf("array subscript out of bounds \n");
#endif


 The #ifdef directive, which conditionally includes source text if a macro name is defined

The #ifdef directive

The #ifdef directive checks for the existence of macro definitions.

If the identifier specified is defined as a macro, the lines of code that immediately follow the
condition are passed on to the compiler.

#ifdef directive syntax

.----------------.
V |
>>-#--ifdef--identifier----token_sequence-+--------------------->

>--newline_character-------------------------------------------><

The following example defines MAX_LEN to be 75 if EXTENDED is defined for the preprocessor.
Otherwise, MAX_LEN is defined to be 50.

#ifdef EXTENDED
# define MAX_LEN 75
#else
# define MAX_LEN 50
#endif


 The #ifndef directive, which conditionally includes source text if a macro name is not
defined

The #ifndef directive

The #ifndef directive checks whether a macro is not defined.


If the identifier specified is not defined as a macro, the lines of code immediately follow the
condition are passed on to the compiler.

#ifndef directive syntax

.----------------.
V |
>>-#--ifndef--identifier----token_sequence-+-------------------->

>--newline_character-------------------------------------------><

An identifier must follow the #ifndef keyword. The following example defines MAX_LEN to be
50 if EXTENDED is not defined for the preprocessor. Otherwise, MAX_LEN is defined to be 75.

#ifndef EXTENDED
# define MAX_LEN 50
#else
# define MAX_LEN 75
#endif


 The #else directive, which conditionally includes source text if the previous #if, #ifdef,
#ifndef, or #elif test fails

The #else directive

If the condition specified in the #if, #ifdef, or #ifndef directive evaluates to 0, and the
conditional compilation directive contains a preprocessor #else directive, the lines of code
located between the preprocessor #else directive and the preprocessor #endif directive is
selected by the preprocessor to be passed on to the compiler.

#else directive syntax

.----------------.
V |
>>-#--else----token_sequence-+--newline_character--------------><


 The #endif directive, which ends conditional text

The #endif directive

The preprocessor #endif directive ends the conditional compilation directive.

#endif directive syntax

>>-#--endif--newline_character---------------------------------><

The preprocessor conditional compilation directive spans several lines:

 The condition specification line (beginning with #if, #ifdef, or #ifndef)


 Lines containing code that the preprocessor passes on to the compiler if the condition
evaluates to a nonzero value (optional)
 The #elif line (optional)
 Lines containing code that the preprocessor passes on to the compiler if the condition
evaluates to a nonzero value (optional)
 The #else line (optional)
 Lines containing code that the preprocessor passes on to the compiler if the condition
evaluates to zero (optional)
 The preprocessor #endif directive

For each #if, #ifdef, and #ifndef directive, there are zero or more #elif directives, zero or
one #else directive, and one matching #endif directive. All the matching directives are
considered to be at the same nesting level.

You can nest conditional compilation directives. In the following directives, the first #else is
matched with the #if directive.

#ifdef MACNAME
/* tokens added if MACNAME is defined */
# if TEST <=10
/* tokens added if MACNAME is defined and TEST <= 10 */
# else
/* tokens added if MACNAME is defined and TEST > 10 */
# endif
#else
/* tokens added if MACNAME is not defined */
#endif

Each directive controls the block immediately following it. A block consists of all the tokens
starting on the line following the directive and ending at the next conditional compilation
directive at the same nesting level.

Each directive is processed in the order in which it is encountered. If an expression evaluates to


zero, the block following the directive is ignored.

When a block following a preprocessor directive is to be ignored, the tokens are examined only
to identify preprocessor directives within that block so that the conditional nesting level can be
determined. All tokens other than the name of the directive are ignored.

Only the first block whose expression is nonzero is processed. The remaining blocks at that
nesting level are ignored. If none of the blocks at that nesting level has been processed and there
is a #else directive, the block following the #else directive is processed. If none of the blocks
at that nesting level has been processed and there is no #else directive, the entire nesting level is
ignored.

Message generation directives


Message generation directives include the following:

 The #error directive, which defines text for a compile-time error message

 A preprocessor error directive causes the preprocessor to generate an error message and
causes the compilation to fail.
 #error directive syntax

 .--------------------.
 V |
 >>-#--error----preprocessor_token-+----------------------------><

 The #error directive is often used in the #else portion of a #if-#elif-#else construct,
as a safety check during compilation. For example, #error directives in the source file
can prevent code generation if a section of the program is reached that should be
bypassed.

 For example, the directive


 #define BUFFER_SIZE 255

 #if BUFFER_SIZE < 256
 #error "BUFFER_SIZE is too small."
 #endif

 generates the error message:


 BUFFER_SIZE is too small.

 The #warning directive, which defines text for a compile-time warning message

The #warning directive

A preprocessor warning directive causes the preprocessor to generate a warning message but
allows compilation to continue. The argument to #warning is not subject to macro expansion.

#warning directive syntax

.--------------------.
V |
>>-#--warning----preprocessor_token-+--------------------------><

The preprocessor #warning directive is a language extension provided to facilitate handling


programs developed with GNU C. The IBM implementation preserves multiple white spaces.


 The #line directive, which supplies a line number for compiler messages

he #line directive

A preprocessor line control directive supplies line numbers for compiler messages. It causes the
compiler to view the line number of the next source line as the specified number.

#line directive syntax

>>-#--line--+-decimal_constant--+-----------------+-+----------><
| '-"--file_name--"-' |
'-characters----------------------------'

In order for the compiler to produce meaningful references to line numbers in preprocessed
source, the preprocessor inserts #line directives where necessary (for example, at the beginning
and after the end of included text).

A file name specification enclosed in double quotation marks can follow the line number. If you
specify a file name, the compiler views the next line as part of the specified file. If you do not
specify a file name, the compiler views the next line as part of the current source file.

At the C99 language level, the maximum value of the #line preprocessing directive is
2147483647.

In all C and C++ implementations, the token sequence on a #line directive is subject to macro
replacement. After macro replacement, the resulting character sequence must consist of a
decimal constant, optionally followed by a file name enclosed in double quotation marks.

You can use #line control directives to make the compiler provide more meaningful error
messages. The following example program uses #line control directives to give each function
an easily recognizable line number:

/**
** This example illustrates #line directives.
**/

#include <stdio.h>
#define LINE200 200

int main(void)
{
func_1();
func_2();
}

#line 100
func_1()
{
printf("Func_1 - the current line number is %d\n",_ _LINE_ _);
}

#line LINE200
func_2()
{
printf("Func_2 - the current line number is %d\n",_ _LINE_ _);
}

This program produces the following output:

Func_1 - the current line number is 102


Func_2 - the current line number is 202

Assertion directives
An assertion directive is an alternative to a macro definition, used to define the computer or
system the compiled program will run on. Assertions are usually predefined, but you can define
them with the #assert preprocessor directive.

#assert directive syntax

>>-#--assert--predicate--(--answer--)--------------------------><

The predicate represents the assertion entity you are defining. The answer represents a value you
are assigning to the assertion. You can make several assertions using the same predicate and
different answers. All the answers for any given predicate are simultaneously true. For example,
the following directives create assertions regarding font properties:

#assert font(arial)
#assert font(blue)

Once an assertion has been defined, the assertion predicate can be used in conditional directives
to test the current system. The following directive tests whether arial or blue is asserted for
font:

#if #font(arial) || #font(blue)

You can test whether any answer is asserted for a predicate by omitting the answer in the
conditional:
#if #font

Assertions can be cancelled with the #unassert directive. If you use the same syntax as the
#assert directive, the directive cancels only the answer you specify. For example, the following
directive cancels the arial answer for the font predicate:

#unassert font(arial)

An entire predicate is cancelled by omitting the answer from the #unassert directive. The
following directive cancels the font directive altogether:

#unassert font

The null directive (#)


The null directive performs no action. It consists of a single # on a line of its own.

The null directive should not be confused with the # operator or the character that starts a
preprocessor directive.

In the following example, if MINVAL is a defined macro name, no action is performed. If MINVAL
is not a defined identifier, it is defined 1.

#ifdef MINVAL
#
#else
#define MINVAL 1
#endif

Related information

 The # operator

The # operator

The # (single number sign) operator converts a parameter of a function-like macro into a
character string literal. For example, if macro ABC is defined using the following directive:

#define ABC(x) #x

all subsequent invocations of the macro ABC would be expanded into a character string literal
containing the argument passed to ABC. For example:

Invocation Result of Macro Expansion

ABC(1) "1"
Invocation Result of Macro Expansion

ABC(Hello there) "Hello there"

The # operator should not be confused with the null directive.

Use the # operator in a function-like macro definition according to the following rules:

 A parameter following # operator in a function- like macro is converted into a character string
literal containing the argument passed to the macro.
 White-space characters that appear before or after the argument passed to the macro are
deleted.
 Multiple white-space characters imbedded within the argument passed to the macro are
replaced by a single space character.
 If the argument passed to the macro contains a string literal and if a \ (backslash) character
appears within the literal, a second \ character is inserted before the original \ when the macro
is expanded.
 If the argument passed to the macro contains a " (double quotation mark) character, a \
character is inserted before the " when the macro is expanded.
 The conversion of an argument into a string literal occurs before macro expansion on that
argument.
 If more than one ## operator or # operator appears in the replacement list of a macro
definition, the order of evaluation of the operators is not defined.
 If the result of the macro expansion is not a valid character string literal, the behavior is
undefined.

The following examples demonstrate the use of the # operator:

#define STR(x) #x
#define XSTR(x) STR(x)
#define ONE 1
Invocation Result of Macro Expansion

STR(\n "\n" '\n') "\n \"\\n\" '\\n'"

STR(ONE) "ONE"

XSTR(ONE) "1"

XSTR("hello") "\"hello\""

Pragma directives
A pragma is an implementation-defined instruction to the compiler. It has the general form:

#pragma directive syntax


.--------------------.
V |
>>-#--pragma--+------+----character_sequence-+--new-line-------><
'-STDC-'

The character_sequence is a series of characters giving a specific compiler instruction and


arguments, if any. The token STDC indicates a standard pragma; consequently, no macro
substitution takes place on the directive. The new-line character must terminate a pragma
directive.

The character_sequence on a pragma is subject to macro substitutions. For example,

#define
XX_ISO_DATA
isolated_call(LG_ISO_DATA)
// ...
#pragma XX_ISO_DATA
Note:
You can also use the _Pragma operator syntax to specify a pragma directive; for details, see The
_Pragma preprocessing operator .

More than one pragma construct can be specified on a single pragma directive. The compiler
ignores unrecognized pragmas.

Type conversions

An expression of a given type is implicitly converted in the following situations:

 The expression is used as an operand of an arithmetic or logical operation.


 The expression is used as a condition in an if statement or an iteration statement (such as a
for loop). The expression will be converted to a Boolean (or an integer in C89).
 The expression is used in a switch statement. The expression will be converted to an integral
type.
 The expression is used as an initialization. This includes the following:
o An assignment is made to an lvalue that has a different type than the assigned value.
o A function is provided an argument value that has a different type than the parameter.
o The value specified in the return statement of a function has a different type from the
defined return type for the function.

You can perform explicit type conversions using a cast expression, as described in Cast
expressions. The following sections discuss the conversions that are allowed by either implicit or
explicit conversion, and the rules governing type promotions:

 Arithmetic conversions and promotions


 Lvalue-to-rvalue conversions
 Pointer conversions
 Reference conversions (C++ only)
 Qualification conversions (C++ only)
 Function argument conversions

Related information

 User-defined conversions (C++ only)


 Conversion by constructor (C++ only)
 Conversion functions (C++ only)
 The switch statement
 The if statement
 The return statement

Reference conversions (C++ only)


A reference conversion can be performed wherever a reference initialization occurs, including
reference initialization done in argument passing and function return values. A reference to a
class can be converted to a reference to an accessible base class of that class as long as the
conversion is not ambiguous. The result of the conversion is a reference to the base class
subobject of the derived class object.

Reference conversion is allowed if the corresponding pointer conversion is allowed.

Related information

 References (C++ only)


 Initialization of references (C++ only)

Initialization of references (C++ only)

The object that you use to initialize a reference must be of the same type as the reference, or it
must be of a type that is convertible to the reference type. If you initialize a reference to a
constant using an object that requires conversion, a temporary object is created. In the following
example, a temporary object of type float is created:

int i;
const float& f = i; // reference to a constant float

When you initialize a reference with an object, you bind that reference to that object.

Attempting to initialize a nonconstant reference with an object that requires a conversion is an


error.

Once a reference has been initialized, it cannot be modified to refer to another object. For
example:
int num1 = 10;
int num2 = 20;

int &RefOne = num1; // valid


int &RefOne = num2; // error, two definitions of RefOne
RefOne = num2; // assign num2 to num1
int &RefTwo; // error, uninitialized reference
int &RefTwo = num2; // valid

Note that the initialization of a reference is not the same as an assignment to a reference.
Initialization operates on the actual reference by initializing the reference with the object it is an
alias for. Assignment operates through the reference on the object referred to.

A reference can be declared without an initializer:

 When it is used in an parameter declaration


 In the declaration of a return type for a function call
 In the declaration of class member within its class declaration
 When the extern specifier is explicitly used

You cannot have references to any of the following:

 Other references
 Bit fields
 Arrays of references
 Pointers to references

Direct binding

Suppose a reference r of type T is initialized by an expression e of type U.

The reference r is bound directly to e if the following statements are true:

 Expression e is an lvalue
 T is the same type as U, or T is a base class of U
 T has the same, or more, const or volatile qualifiers than U

The reference r is also bound directly to e if e can be implicitly converted to a type such that the
previous list of statements is true.

Related information

 References (C++ only)


 Pass by reference


 Function calls
 Function return values
References (C++ only)
A reference is an alias or an alternative name for an object. All operations applied to a reference
act on the object to which the reference refers. The address of a reference is the address of the
aliased object.

A reference type is defined by placing the reference modifier & after the type specifier. You must
initialize all references except function parameters when they are defined. Once defined, a
reference cannot be reassigned because it is an alias to its target. What happens when you try to
reassign a reference turns out to be the assignment of a new value to the target.

Because arguments of a function are passed by value, a function call does not modify the actual
values of the arguments. If a function needs to modify the actual value of an argument or needs
to return more than one value, the argument must be passed by reference (as opposed to being
passed by value). Passing arguments by reference can be done using either references or pointers.
Unlike C, C++ does not force you to use pointers if you want to pass arguments by reference.
The syntax of using a reference is somewhat simpler than that of using a pointer. Passing an
object by reference enables the function to change the object being referred to without creating a
copy of the object within the scope of the function. Only the address of the actual original object
is put on the stack, not the entire object.

For example:

int f(int&);
int main()
{
extern int i;
f(i);
}

You cannot tell from the function call f(i) that the argument is being passed by reference.

References to NULL are not allowed.

Qualification conversions (C++ only)


An type-qualified rvalue of any type, containing zero or more const or volatile qualifications,
can be converted to an rvalue of type-qualified type where the second rvalue contains more
const or volatile qualifications than the first rvalue.

An rvalue of type pointer to member of a class can be converted to an rvalue of type pointer to
member of a class if the second rvalue contains more const or volatile qualifications than the
first rvalue.

Related information
 Type qualifiers

Type qualifiers
A type qualifier is used to refine the declaration of a variable, a function, and parameters, by
specifying whether:

 The value of an object can be changed


 The value of an object must always be read from memory rather than from a register
 More than one pointer can access a modifiable memory address

XL C/C++ recognizes the following type qualifiers:

 const
 volatile
 restrict
 __align

Standard C++ refers to the type qualifiers const and volatile as cv-qualifiers. In both
languages, the cv-qualifiers are only meaningful in expressions that are lvalues.

When the const and volatile keywords are used with pointers, the placement of the qualifier is
critical in determining whether it is the pointer itself that is to be qualified, or the object to which
the pointer points. For a pointer that you want to qualify as volatile or const, you must put the
keyword between the * and the identifier. For example:

int * volatile x; /* x is a volatile pointer to an int */


int * const y = &z; /* y is a const pointer to the int variable z
*/

For a pointer to a volatile or const data object, the type specifier and qualifier can be in any
order, provided that the qualifier does not follow the * operator. For example:

volatile int *x; /* x is a pointer to a volatile int


or */
int volatile *x; /* x is a pointer to a volatile int */

const int *y; /* y is a pointer to a const int


or */
int const *y; /* y is a pointer to a const int */

The following examples contrast the semantics of these declarations:

Declaration Description
const int * ptr1;
Defines a pointer to a constant integer: the value
pointed to cannot be changed.
Declaration Description
Defines a constant pointer to an integer: the integer
int * const ptr2; can be changed, but ptr2 cannot point to anything
else.
Defines a constant pointer to a constant integer:
const int * const ptr3; neither the value pointed to nor the pointer itself can
be changed.

You can put more than one qualifier on a declaration: the compiler ignores duplicate type
qualifiers.

A type qualifier cannot apply to user-defined types, but only to objects created from a user-
defined type. Therefore, the following declaration is illegal:

volatile struct omega {


int limit;
char code;
}

However, if a variable or variables are declared within the same definition of the type, a type
qualifier can be applied to the variable or variables by placing at the beginning of the statement
or before the variable declarator or declarators. Therefore:

volatile struct omega {


int limit;
char code;
} group;

provides the same storage as:

struct omega {
int limit;
char code;
} volatile group;

In both examples, the volatile qualifier only applies to the structure variable group.

When type qualifiers are applied to a structure, class, or union, or class variable, they also apply
to the members of the structure, class or union.

Related information

 Pointers
 Constant and volatile member functions (C++ only)

User-defined conversions (C++ only)


User-defined conversions allow you to specify object conversions with constructors or with
conversion functions. User-defined conversions are implicitly used in addition to standard
conversions for conversion of initializers, functions arguments, function return values,
expression operands, expressions controlling iteration, selection statements, and explicit type
conversions.

There are two types of user-defined conversions:

 Conversion by constructor
 Conversion functions

The compiler can use only one user-defined conversion (either a conversion constructor or a
conversion function) when implicitly converting a single value. The following example
demonstrates this:

class A {
int x;
public:
operator int() { return x; };
};

class B {
A y;
public:
operator A() { return y; };
};

int main () {
B b_obj;
// int i = b_obj;
int j = A(b_obj);
}

The compiler would not allow the statement int i = b_obj. The compiler would have to
implicitly convert b_obj into an object of type A (with B::operator A()), then implicitly
convert that object to an integer (with A::operator int()). The statement int j = A(b_obj)
explicitly converts b_obj into an object of type A, then implicitly converts that object to an
integer.

User-defined conversions must be unambiguous, or they are not called. A conversion function in
a derived class does not hide another conversion function in a base class unless both conversion
functions convert to the same type. Function overload resolution selects the most appropriate
conversion function. The following example demonstrates this:

class A {
int a_int;
char* a_carp;
public:
operator int() { return a_int; }
operator char*() { return a_carp; }
};

class B : public A {
float b_float;
char* b_carp;
public:
operator float() { return b_float; }
operator char*() { return b_carp; }
};

int main () {
B b_obj;
// long a = b_obj;
char* c_p = b_obj;
}

The compiler would not allow the statement long a = b_obj. The compiler could either use
A::operator int() or B::operator float() to convert b_obj into a long. The statement
char* c_p = b_obj uses B::operator char*() to convert b_obj into a char* because
B::operator char*() hides A::operator char*().

When you call a constructor with an argument and you have not defined a constructor accepting
that argument type, only standard conversions are used to convert the argument to another
argument type acceptable to a constructor for that class. No other constructors or conversions
functions are called to convert the argument to a type acceptable to a constructor defined for that
class. The following example demonstrates this:

class A {
public:
A() { }
A(int) { }
};

int main() {
A a1 = 1.234;
// A moocow = "text string";
}

The compiler allows the statement A a1 = 1.234. The compiler uses the standard conversion of
converting 1.234 into an int, then implicitly calls the converting constructor A(int). The
compiler would not allow the statement A moocow = "text string"; converting a text string to
an integer is not a standard conversion.

Related information

 Type conversions
Conversion by constructor (C++ only)

A converting constructor is a single-parameter constructor that is declared without the function


specifier explicit. The compiler uses converting constructors to convert objects from the type
of the first parameter to the type of the converting constructor's class. The following example
demonstrates this:

class Y {
int a, b;
char* name;
public:
Y(int i) { };
Y(const char* n, int j = 0) { };
};

void add(Y) { };

int main() {

// equivalent to
// obj1 = Y(2)
Y obj1 = 2;

// equivalent to
// obj2 = Y("somestring",0)
Y obj2 = "somestring";

// equivalent to
// obj1 = Y(10)
obj1 = 10;

// equivalent to
// add(Y(5))
add(5);
}

The above example has the following two converting constructors:

 Y(int i)which is used to convert integers to objects of class Y.


 Y(const char* n, int j = 0) which is used to convert pointers to strings to objects of
class Y.

The compiler will not implicitly convert types as demonstrated above with constructors declared
with the explicit keyword. The compiler will only use explicitly declared constructors in new
expressions, the static_cast expressions and explicit casts, and the initialization of bases and
members. The following example demonstrates this:

class A {
public:
explicit A() { };
explicit A(int) { };
};
int main() {
A z;
// A y = 1;
A x = A(1);
A w(1);
A* v = new A(1);
A u = (A)1;
A t = static_cast<A>(1);
}

The compiler would not allow the statement A y = 1 because this is an implicit conversion;
class A has no conversion constructors.

A copy constructor is a converting constructor.

Related information

 The new operator (C++ only)


 The static_cast operator (C++ only)

Conversion functions (C++ only)

You can define a member function of a class, called a conversion function, that converts from the
type of its class to another specified type.

Conversion function syntax

>>-+-----------+--operator--+----------+--conversion_type------->
'-class--::-' +-const----+
'-volatile-'

>--+----------------------+--(--)--+---------------------+-----><
| .------------------. | '-{--function_body--}-'
| V | |
'---pointer_operator-+-'

A conversion function that belongs to a class X specifies a conversion from the class type X to the
type specified by the conversion_type. The following code fragment shows a conversion
function called operator int():

class Y {
int b;
public:
operator int();
};
Y::operator int() {
return b;
}
void f(Y obj) {
int i = int(obj);
int j = (int)obj;
int k = i + obj;
}

All three statements in function f(Y) use the conversion function Y::operator int().

Classes, enumerations, typedef names, function types, or array types cannot be declared or
defined in the conversion_type. You cannot use a conversion function to convert an object of
type A to type A, to a base class of A, or to void.

Conversion functions have no arguments, and the return type is implicitly the conversion type.
Conversion functions can be inherited. You can have virtual conversion functions but not static
ones.

Namespaces (C++ only)

A namespace is an optionally named scope. You declare names inside a namespace as you would
for a class or an enumeration. You can access names declared inside a namespace the same way
you access a nested class name by using the scope resolution (::) operator. However
namespaces do not have the additional features of classes or enumerations. The primary purpose
of the namespace is to add an additional identifier (the name of the namespace) to a name.

Scope resolution operator :: (C++ only)

The :: (scope resolution) operator is used to qualify hidden names so that you can still use them.
You can use the unary scope operator if a namespace scope or global scope name is hidden by an
explicit declaration of the same name in a block or class. For example:

int count = 0;

int main(void) {
int count = 0;
::count = 1; // set global count to 1
count = 2; // set local count to 2
return 0;
}

The declaration of count declared in the main function hides the integer named count declared
in global namespace scope. The statement ::count = 1 accesses the variable named count
declared in global namespace scope.

You can also use the class scope operator to qualify class names or class member names. If a
class member name is hidden, you can use it by qualifying it with its class name and the class
scope operator.
In the following example, the declaration of the variable X hides the class type X, but you can still
use the static class member count by qualifying it with the class type X and the scope resolution
operator.

#include <iostream>
using namespace std;

class X
{
public:
static int count;
};
int X::count = 10; // define static data member

int main ()
{
int X = 0; // hides class type X
cout << X::count << endl; // use static member of class X
}

Related information

 Scope of class names (C++ only)


 Namespaces (C++ only)

Overloading (C++ only)

If you specify more than one definition for a function name or an operator in the same scope, you
have overloaded that function name or operator. Overloaded functions and operators are
described in Overloading functions (C++ only) and Overloading operators (C++ only),
respectively.

An overloaded declaration is a declaration that had been declared with the same name as a
previously declared declaration in the same scope, except that both declarations have different
types.

If you call an overloaded function name or operator, the compiler determines the most
appropriate definition to use by comparing the argument types you used to call the function or
operator with the parameter types specified in the definitions. The process of selecting the most
appropriate overloaded function or operator is called overload resolution, as described in
Overload resolution (C++ only).

Overloading functions (C++ only)


You overload a function name f by declaring more than one function with the name f in the
same scope. The declarations of f must differ from each other by the types and/or the number of
arguments in the argument list. When you call an overloaded function named f, the correct
function is selected by comparing the argument list of the function call with the parameter list of
each of the overloaded candidate functions with the name f. A candidate function is a function
that can be called based on the context of the call of the overloaded function name.

Consider a function print, which displays an int. As shown in the following example, you can
overload the function print to display other types, for example, double and char*. You can
have three functions with the same name, each performing a similar operation on a different data
type:

#include <iostream>
using namespace std;

void print(int i) {
cout << " Here is int " << i << endl;
}
void print(double f) {
cout << " Here is float " << f << endl;
}

void print(char* c) {
cout << " Here is char* " << c << endl;
}

int main() {
print(10);
print(10.10);
print("ten");
}

The following is the output of the above example:

Here is int 10
Here is float 10.1
Here is char* ten

Function overloading based on vector parameter types is supported.

Restrictions on overloaded functions (C++ only)

You cannot overload the following function declarations if they appear in the same scope. Note
that this list applies only to explicitly declared functions and those that have been introduced
through using declarations:

 Function declarations that differ only by return type. For example, you cannot declare the
following declarations:
 int f();
float f();
 Member function declarations that have the same name and the same parameter types, but one
of these declarations is a static member function declaration. For example, you cannot declare
the following two member function declarations of f():
 struct A {
 static int f();
 int f();
};

 Member function template declarations that have the same name, the same parameter types,
and the same template parameter lists, but one of these declarations is a static template
member function declaration.
 Function declarations that have equivalent parameter declarations. These declarations are not
allowed because they would be declaring the same function.
 Function declarations with parameters that differ only by the use of typedef names that
represent the same type. Note that a typedef is a synonym for another type, not a separate
type. For example, the following two declarations of f() are declarations of the same function:
 typedef int I;
 void f(float, int);
 void f(float, I);
 Function declarations with parameters that differ only because one is a pointer and the other is
an array. For example, the following are declarations of the same function:
 f(char*);
 f(char[10]);

The first array dimension is insignificant when differentiating parameters; all other array
dimensions are significant. For example, the following are declarations of the same function:

g(char(*)[20]);
g(char[5][20]);

The following two declarations are not equivalent:

g(char(*)[20]);
g(char(*)[40]);

 Function declarations with parameters that differ only because one is a function type and the
other is a pointer to a function of the same type. For example, the following are declarations of
the same function:
 void f(int(float));
void f(int (*)(float));

 Function declarations with parameters that differ only because of cv-qualifiers const,
volatile, and restrict. This restriction only applies if any of these qualifiers appears at the
outermost level of a parameter type specification. For example, the following are declarations of
the same function:
 int f(int);
 int f(const int);
int f(volatile int);
Note that you can differentiate parameters with const, volatile and restrict qualifiers if
you apply them within a parameter type specification. For example, the following declarations
are not equivalent because const and volatile qualify int, rather than *, and thus are not at
the outermost level of the parameter type specification.

void g(int*);
void g(const int*);
void g(volatile int*);

The following declarations are also not equivalent:

void g(float&);
void g(const float&);
void g(volatile float&);

 Function declarations with parameters that differ only because their default arguments differ.
For example, the following are declarations of the same function:
 void f(int);
void f(int i = 10);

 Multiple functions with extern "C" language-linkage and the same name, regardless of
whether their parameter lists are different.

Related information

 The using declaration and namespaces (C++ only)


 typedef definitions
 Type qualifiers
 Language linkage (C++ only)

Derivation (C++ only)


Inheritance is implemented in C++ through the mechanism of derivation. Derivation allows you
to derive a class, called a derived class, from another class, called a base class.

Derived class syntax

>>-derived_class--:--------------------------------------------->

.-,---------------------------------------------------------.
V |
>----+----------------------------+--qualified_class_specifier-+-><
+-virtual--+-----------+-----+
| +-public----+ |
| +-private---+ |
| '-protected-' |
'-+-public----+--+---------+-'
+-private---+ '-virtual-'
'-protected-'
In the declaration of a derived class, you list the base classes of the derived class. The derived
class inherits its members from these base classes.

The qualified_class_specifier must be a class that has been previously declared in a class
declaration.

An access specifier is one of public, private, or protected.

The virtual keyword can be used to declare virtual base classes.

The following example shows the declaration of the derived class D and the base classes V, B1,
and B2. The class B1 is both a base class and a derived class because it is derived from class V
and is a base class for D:

class V { /* ... */ };
class B1 : virtual public V { /* ... */ };
class B2 { /* ... */ };
class D : public B1, private B2 { /* ... */ };

Classes that are declared but not defined are not allowed in base lists.

For example:

class X;

// error
class Y: public X { };

The compiler will not allow the declaration of class Y because X has not been defined.

When you derive a class, the derived class inherits class members of the base class. You can
refer to inherited members (base class members) as if they were members of the derived class.
For example:

class Base {
public:
int a,b;
};

class Derived : public Base {


public:
int c;
};

int main() {
Derived d;
d.a = 1; // Base::a
d.b = 2; // Base::b
d.c = 3; // Derived::c
}

The derived class can also add new class members and redefine existing base class members. In
the above example, the two inherited members, a and b, of the derived class d, in addition to the
derived class member c, are assigned values. If you redefine base class members in the derived
class, you can still refer to the base class members by using the :: (scope resolution) operator.
For example:

#include <iostream>
using namespace std;

class Base {
public:
char* name;
void display() {
cout << name << endl;
}
};

class Derived: public Base {


public:
char* name;
void display() {
cout << name << ", " << Base::name << endl;
}
};

int main() {
Derived d;
d.name = "Derived Class";
d.Base::name = "Base Class";

// call Derived::display()
d.display();

// call Base::display()
d.Base::display();
}

The following is the output of the above example:

Derived Class, Base Class


Base Class

You can manipulate a derived class object as if it were a base class object. You can use a pointer
or a reference to a derived class object in place of a pointer or reference to its base class. For
example, you can pass a pointer or reference to a derived class object D to a function expecting a
pointer or reference to the base class of D. You do not need to use an explicit cast to achieve this;
a standard conversion is performed. You can implicitly convert a pointer to a derived class to
point to an accessible unambiguous base class. You can also implicitly convert a reference to a
derived class to a reference to a base class.
The following example demonstrates a standard conversion from a pointer to a derived class to a
pointer to a base class:

#include <iostream>
using namespace std;

class Base {
public:
char* name;
void display() {
cout << name << endl;
}
};

class Derived: public Base {


public:
char* name;
void display() {
cout << name << ", " << Base::name << endl;
}
};

int main() {
Derived d;
d.name = "Derived Class";
d.Base::name = "Base Class";

Derived* dptr = &d;

// standard conversion from Derived* to Base*


Base* bptr = dptr;

// call Base::display()
bptr->display();
}

The following is the output of the above example:

Base Class

The statement Base* bptr = dptr converts a pointer of type Derived to a pointer of type Base.

The reverse case is not allowed. You cannot implicitly convert a pointer or a reference to a base
class object to a pointer or reference to a derived class. For example, the compiler will not allow
the following code if the classes Base and Class are defined as in the above example:

int main() {
Base b;
b.name = "Base class";

Derived* dptr = &b;


}
The compiler will not allow the statement Derived* dptr = &b because the statement is trying
to implicitly convert a pointer of type Base to a pointer of type Derived.

If a member of a derived class and a member of a base class have the same name, the base class
member is hidden in the derived class. If a member of a derived class has the same name as a
base class, the base class name is hidden in the derived class.

Related information

 Virtual base classes (C++ only)


 Inherited member access (C++ only)
 Incomplete class declarations (C++ only)
 Scope resolution operator :: (C++ only)

Virtual base classes (C++ only)

Suppose you have two derived classes B and C that have a common base class A, and you also
have another class D that inherits from B and C. You can declare the base class A as virtual to
ensure that B and C share the same subobject of A.

In the following example, an object of class D has two distinct subobjects of class L, one through
class B1 and another through class B2. You can use the keyword virtual in front of the base
class specifiers in the base lists of classes B1 and B2 to indicate that only one subobject of type L,
shared by class B1 and class B2, exists.

For example:

class L { /* ... */ }; // indirect base class


class B1 : virtual public L { /* ... */ };
class B2 : virtual public L { /* ... */ };
class D : public B1, public B2 { /* ... */ }; // valid

Using the keyword virtual in this example ensures that an object of class D inherits only one
subobject of class L.

A derived class can have both virtual and nonvirtual base classes. For example:
class V { /* ... */ };
class B1 : virtual public V { /* ... */ };
class B2 : virtual public V { /* ... */ };
class B3 : public V { /* ... */ };
class X : public B1, public B2, public B3 { /* ... */
};

In the above example, class X has two subobjects of class V, one that is shared by classes B1 and
B2 and one through class B3.

Related information

 Derivation (C++ only)

Overloading operators (C++ only)


You can redefine or overload the function of most built-in operators in C++. These operators can
be overloaded globally or on a class-by-class basis. Overloaded operators are implemented as
functions and can be member functions or global functions.

Operator overloading involving vector types is not supported.

An overloaded operator is called an operator function. You declare an operator function with the
keyword operator preceding the operator. Overloaded operators are distinct from overloaded
functions, but like overloaded functions, they are distinguished by the number and types of
operands used with the operator.

Consider the standard + (plus) operator. When this operator is used with operands of different
standard types, the operators have slightly different meanings. For example, the addition of two
integers is not implemented in the same way as the addition of two floating-point numbers. C++
allows you to define your own meanings for the standard C++ operators when they are applied to
class types. In the following example, a class called complx is defined to model complex
numbers, and the + (plus) operator is redefined in this class to add two complex numbers.

// This example illustrates overloading the plus (+) operator.

#include <iostream>
using namespace std;
class complx
{
double real,
imag;
public:
complx( double real = 0., double imag = 0.); // constructor
complx operator+(const complx&) const; // operator+()
};

// define constructor
complx::complx( double r, double i )
{
real = r; imag = i;
}

// define overloaded + (plus) operator


complx complx::operator+ (const complx& c) const
{
complx result;
result.real = (this->real + c.real);
result.imag = (this->imag + c.imag);
return result;
}

int main()
{
complx x(4,4);
complx y(6,6);
complx z = x + y; // calls complx::operator+()
}

You can overload any of the following operators:

+ - * / % ^ & | ~
! = < > += -= *= /= %=
^= &= |= << >> <<= >>= == !=
<= >= && || ++ -- , ->* ->
() [] new delete new[] delete[]      

where () is the function call operator and [] is the subscript operator.

You can overload both the unary and binary forms of the following operators:

+ - * &

You cannot overload the following operators:

. .* :: ?:
You cannot overload the preprocessor symbols # and ##.

An operator function can be either a nonstatic member function, or a nonmember function with
at least one parameter that has class, reference to class, enumeration, or reference to enumeration
type.

You cannot change the precedence, grouping, or the number of operands of an operator.

An overloaded operator (except for the function call operator) cannot have default arguments or
an ellipsis in the argument list.

You must declare the overloaded =, [], (), and -> operators as nonstatic member functions to
ensure that they receive lvalues as their first operands.

The operators new, delete, new[], and delete[] do not follow the general rules described in
this section.

All operators except the = operator are inherited.

Related information

 Free store (C++ only)

Free store (C++ only)


Free store is a pool of memory available for you to allocate (and deallocate) storage for objects
during the execution of your program. The new and delete operators are used to allocate and
deallocate free store, respectively.

You can define your own versions of new and delete for a class by overloading them. You can
declare the new and delete operators with additional parameters. When new and delete operate
on class objects, the class member operator functions new and delete are called, if they have
been declared.

If you create a class object with the new operator, one of the operator functions operator new()
or operator new[]() (if they have been declared) is called to create the object. An operator
new() or operator new[]() for a class is always a static class member, even if it is not declared
with the keyword static. It has a return type void* and its first parameter must be the size of
the object type and have type std::size_t. It cannot be virtual.

Type std::size_t is an implementation-dependent unsigned integral type defined in the


standard library header <cstddef>. When you overload the new operator, you must declare it as
a class member, returning type void*, with its first parameter of type std::size_t. You can
declare additional parameters in the declaration of operator new() or operator new[](). Use
the placement syntax to specify values for these parameters in an allocation expression.
The following example overloads two operator new functions:

 X::operator new(size_t sz): This overloads the default new operator by allocating
memory with the C function malloc(), and throwing a string (instead of
std::bad_alloc) if malloc() fails.
 X::operator new(size_t sz, int location): This function takes an additional
integer parameter, location. This function implements a very simplistic "memory
manager" that manages the storage of up to three X objects.

Static array X::buffer holds three Node objects. Each Node object contains a pointer to
an X object named data and a Boolean variable named filled. Each X object stores an
integer called number.

When you use this new operator, you pass the argument location which indicates the
array location of buffer where you want to "create" your new X object. If the array
location is not "filled" (the data member of filled is equal to false at that array
location), the new operator returns a pointer pointing to the X object located at
buffer[location].

#include <new>
#include <iostream>

using namespace std;

class X;

struct Node {
X* data;
bool filled;
Node() : filled(false) { }
};

class X {
static Node buffer[];

public:

int number;

enum { size = 3};

void* operator new(size_t sz) throw (const char*) {


void* p = malloc(sz);
if (sz == 0) throw "Error: malloc() failed";
cout << "X::operator new(size_t)" << endl;
return p;
}

void *operator new(size_t sz, int location) throw (const char*) {


cout << "X::operator new(size_t, " << location << ")" << endl;
void* p = 0;
if (location < 0 || location >= size || buffer[location].filled == true) {
throw "Error: buffer location occupied";
}
else {
p = malloc(sizeof(X));
if (p == 0) throw "Error: Creating X object failed";
buffer[location].filled = true;
buffer[location].data = (X*) p;
}
return p;
}

static void printbuffer() {


for (int i = 0; i < size; i++) {
cout << buffer[i].data->number << endl;
}
}

};

Node X::buffer[size];

int main() {
try {
X* ptr1 = new X;
X* ptr2 = new(0) X;
X* ptr3 = new(1) X;
X* ptr4 = new(2) X;
ptr2->number = 10000;
ptr3->number = 10001;
ptr4->number = 10002;
X::printbuffer();
X* ptr5 = new(0) X;
}
catch (const char* message) {
cout << message << endl;
}
}

The following is the output of the above example:

X::operator new(size_t)
X::operator new(size_t, 0)
X::operator new(size_t, 1)
X::operator new(size_t, 2)
10000
10001
10002
X::operator new(size_t, 0)
Error: buffer location occupied

The statement X* ptr1 = new X calls X::operator new(sizeof(X)). The statement X* ptr2
= new(0) X calls X::operator new(sizeof(X),0).
The delete operator destroys an object created by the new operator. The operand of delete
must be a pointer returned by new. If delete is called for an object with a destructor, the
destructor is invoked before the object is deallocated.

If you destroy a class object with the delete operator, the operator function operator
delete() or operator delete[]() (if they have been declared) is called to destroy the object.
An operator delete() or operator delete[]() for a class is always a static member, even if
it is not declared with the keyword static. Its first parameter must have type void*. Because
operator delete() and operator delete[]() have a return type void, they cannot return a
value.

The following example shows the declaration and use of the operator functions operator new()
and operator delete():

#include <cstdlib>
#include <iostream>
using namespace std;

class X {
public:
void* operator new(size_t sz) throw (const char*) {
void* p = malloc(sz);
if (p == 0) throw "malloc() failed";
return p;
}

// single argument
void operator delete(void* p) {
cout << "X::operator delete(void*)" << endl;
free(p);
}

};

class Y {
int filler[100];
public:

// two arguments
void operator delete(void* p, size_t sz) throw (const char*) {
cout << "Freeing " << sz << " byte(s)" << endl;
free(p);
};

};

int main() {
X* ptr = new X;

// call X::operator delete(void*)


delete ptr;

Y* yptr = new Y;
// call Y::operator delete(void*, size_t)
// with size of Y as second argument
delete yptr;
}

The above example will generate output similar to the following:

X::operator delete(void*)
Freeing 400 byte(s)

The statement delete ptr calls X::operator delete(void*). The statement delete yptr calls
Y::operator delete(void*, size_t).

The result of trying to access a deleted object is undefined because the value of the object can
change after deletion.

If new and delete are called for a class object that does not declare the operator functions new
and delete, or they are called for a nonclass object, the global operators new and delete are
used. The global operators new and delete are provided in the C++ library.

The C++ operators for allocating and deallocating arrays of class objects are operator new[ ]
() and operator delete[ ]().

You cannot declare the delete operator as virtual. However you can add polymorphic behavior
to your delete operators by declaring the destructor of a base class as virtual. The following
example demonstrates this:

#include <iostream>
using namespace std;

struct A {
virtual ~A() { cout << "~A()" << endl; };
void operator delete(void* p) {
cout << "A::operator delete" << endl;
free(p);
}
};

struct B : A {
void operator delete(void* p) {
cout << "B::operator delete" << endl;
free(p);
}
};

int main() {
A* ap = new B;
delete ap;
}
The following is the output of the above example:

~A()
B::operator delete

The statement delete ap uses the delete operator from class B instead of class A because the
destructor of A has been declared as virtual.

Although you can get polymorphic behavior from the delete operator, the delete operator that
is statically visible must still be accessible even though another delete operator might be called.
For example, in the above example, the function A::operator delete(void*) must be
accessible even though the example calls B::operator delete(void*) instead.

Virtual destructors do not have any affect on deallocation operators for arrays (operator
delete[]()). The following example demonstrates this:

#include <iostream>
using namespace std;

struct A {
virtual ~A() { cout << "~A()" << endl; }
void operator delete[](void* p, size_t) {
cout << "A::operator delete[]" << endl;
::delete [] p;
}
};

struct B : A {
void operator delete[](void* p, size_t) {
cout << "B::operator delete[]" << endl;
::delete [] p;
}
};

int main() {
A* bp = new B[3];
delete[] bp;
};

The behavior of the statement delete[] bp is undefined.

When you overload the delete operator, you must declare it as class member, returning type
void, with the first parameter having type void*, as described above. You can add a second
parameter of type size_t to the declaration. You can only have one operator delete() or
operator delete[]() for a single class.

Related information

 The new operator (C++ only)


The new operator (C++ only)

The new operator provides dynamic storage allocation.

new operator syntax

>>-+----+--new--+---------------------+--+-(--type--)-+--------->
'-::-' '-(--argument_list--)-' '-new_type---'

>--+-------------------------+---------------------------------><
'-(--+---------------+--)-'
'-initial_value-'

If you prefix new with the scope resolution operator (::), the global operator new() is used. If
you specify an argument_list, the overloaded new operator that corresponds to that argument_list
is used. The type is an existing built-in or user-defined type. A new_type is a type that has not
already been defined and can include type specifiers and declarators.

An allocation expression containing the new operator is used to find storage in free store for the
object being created. The new expression returns a pointer to the object created and can be used
to initialize the object. If the object is an array, a pointer to the initial element is returned.

You cannot use the new operator to allocate function types, void, or incomplete class types
because these are not object types. However, you can allocate pointers to functions with the new
operator. You cannot create a reference with the new operator.

When the object being created is an array, only the first dimension can be a general expression.
All subsequent dimensions must be constant integral expressions. The first dimension can be a
general expression even when an existing type is used. You can create an array with zero bounds
with the new operator. For example:

char * c = new char[0];

In this case, a pointer to a unique object is returned.

An object created with operator new() or operator new[]() exists until the operator
delete() or operator delete[]() is called to deallocate the object's memory. A delete
operator or a destructor will not be implicitly called for an object created with a new that has not
been explicitly deallocated before the end of the program.

If parentheses are used within a new type, parentheses should also surround the new type to
prevent syntax errors.

In the following example, storage is allocated for an array of pointers to functions:

void f();
void g();
int main(void)
{
void (**p)(), (**q)();
// declare p and q as pointers to pointers to void functions
p = new (void (*[3])());
// p now points to an array of pointers to functions
q = new void(*[3])(); // error
// error - bound as 'q = (new void) (*[3])();'
p[0] = f; // p[0] to point to function f
q[2] = g; // q[2] to point to function g
p[0](); // call f()
q[2](); // call g()
return (0);
}

However, the second use of new causes an erroneous binding of q = (new void) (*[3])().

The type of the object being created cannot contain class declarations, enumeration declarations,
or const or volatile types. It can contain pointers to const or volatile objects.

For example, const char* is allowed, but char* const is not.

Placement syntax

Arguments specifying an allocated storage location can be supplied to new by using the
argument_list, also called the placement syntax. If placement arguments are used, a declaration
of operator new() or operator new[]() with these arguments must exist. For example:

#include <new>
using namespace std;

class X
{
public:
void* operator new(size_t,int, int){ /* ... */ }
};

// ...

int main ()
{
X* ptr = new(1,2) X;
}

The placement syntax is commonly used to invoke the global placement new function. The
global placement new function initializes an object or objects at the location specified by the
placement argument in the placement new expression. This location must address storage that
has previously been allocated by some other means, because the global placement new function
does not itself allocate memory. In the following example, no new memory is allocated by the
calls new(whole) X(8);, new(seg2) X(9);, or new(seg3) X(10); Instead, the constructors
X(8), X(9), and X(10) are called to reinitialize the memory allocated to the buffer whole.

Because placement new does not allocate memory, you should not use delete to deallocate
objects created with the placement syntax. You can only delete the entire memory pool (delete
whole). In the example, you can keep the memory buffer but destroy the object stored in it by
explicitly calling a destructor.

#include <new>
class X
{
public:
X(int n): id(n){ }
~X(){ }
private:
int id;
// ...
};

int main()
{
char* whole = new char[ 3 * sizeof(X) ]; // a 3-part buffer
X * p1 = new(whole) X(8); // fill the front
char* seg2 = &whole[ sizeof(X) ]; // mark second segment
X * p2 = new(seg2) X(9); // fill second segment
char* seg3 = &whole[ 2 * sizeof(X) ]; // mark third segment
X * p3 = new(seg3) X(10); // fill third segment

p2->~X(); // clear only middle segment, but keep the buffer


// ...
return 0;
}

The placement new syntax can also be used for passing parameters to an allocation routine rather
than to a constructor.

Related information

 Free store (C++ only)


 The delete operator (C++ only)
 Scope resolution operator :: (C++ only)
 Overview of constructors and destructors (C++ only)


 The delete operator (C++ only)

The delete operator (C++ only)

The delete operator destroys the object created with new by deallocating the memory associated
with the object.
The delete operator has a void return type.

delete operator syntax

>>-+----+--delete--object_pointer------------------------------><
'-::-'

The operand of delete must be a pointer returned by new, and cannot be a pointer to constant.
Deleting a null pointer has no effect.

The delete[] operator frees storage allocated for array objects created with new[]. The delete
operator frees storage allocated for individual objects created with new.

delete[] operator syntax

>>-+----+--delete--[--]--array---------------------------------><
'-::-'

The result of deleting an array object with delete is undefined, as is deleting an individual
object with delete[]. The array dimensions do not need to be specified with delete[].

The result of any attempt to access a deleted object or array is undefined.

If a destructor has been defined for a class, delete invokes that destructor. Whether a destructor
exists or not, delete frees the storage pointed to by calling the function operator delete() of
the class if one exists.

The global ::operator delete() is used if:

 The class has no operator delete().


 The object is of a nonclass type.
 The object is deleted with the ::delete expression.

The global ::operator delete[]() is used if:

 The class has no operator delete[]()


 The object is of a nonclass type
 The object is deleted with the ::delete[] expression.

The default global operator delete() only frees storage allocated by the default global
operator new(). The default global operator delete[]() only frees storage allocated for
arrays by the default global operator new[]().

Related information

 Free store (C++ only)


 Overview of constructors and destructors (C++ only)
 The void type
 Overload resolution (C++ only)
 The process of selecting the most appropriate overloaded function or operator is called
overload resolution.
 Suppose that f is an overloaded function name. When you call the overloaded function
f(), the compiler creates a set of candidate functions. This set of functions includes all of
the functions named f that can be accessed from the point where you called f(). The
compiler may include as a candidate function an alternative representation of one of those
accessible functions named f to facilitate overload resolution.
 After creating a set of candidate functions, the compiler creates a set of viable functions.
This set of functions is a subset of the candidate functions. The number of parameters of
each viable function agrees with the number of arguments you used to call f().
 The compiler chooses the best viable function, the function declaration that the C++ run-
time environment will use when you call f(), from the set of viable functions. The
compiler does this by implicit conversion sequences. An implicit conversion sequence is
the sequence of conversions required to convert an argument in a function call to the type
of the corresponding parameter in a function declaration. The implicit conversion
sequences are ranked; some implicit conversion sequences are better than others. The
best viable function is the one whose parameters all have either better or equal-ranked
implicit conversion sequences than all of the other viable functions. The compiler will not
allow a program in which the compiler was able to find more than one best viable
function. Implicit conversion sequences are described in more detail in Implicit
conversion sequences (C++ only).
 When a variable length array is a function parameter, the leftmost array dimension does
not distinguish functions among candidate functions. In the following, the second
definition of f is not allowed because void f(int []) has already been defined.
 void f(int a[*]) {}
 void f(int a[5]) {} // illegal
 However, array dimensions other than the leftmost in a variable length array do
differentiate candidate functions when the variable length array is a function parameter.
For example, the overload set for function f might comprise the following:
 void f(int a[][5]) {}
 void f(int a[][4]) {}
 void f(int a[][g]) {} // assume g is a global int
 but cannot include
 void f(int a[][g2]) {} // illegal, assuming g2 is a global int
 because having candidate functions with second-level array dimensions g and g2 creates
ambiguity about which function f should be called: neither g nor g2 is known at compile
time.
 You can override an exact match by using an explicit cast. In the following example, the
second call to f() matches with f(void*):
 void f(int) { };
 void f(void*) { };

 int main() {
 f(0xaabb); // matches f(int);
 f((void*) 0xaabb); // matches f(void*)
 }

You might also like