OOPS Interview Questions

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 58

OOPS Interview Questions

1) Explain the rationale behind Object Oriented concepts?


Object oriented concepts form the base of all modern programming languages. Understanding
the basic concepts of object-orientation helps a developer to use various modern day
programming languages, more effectively.
2) Explain about Object oriented programming?
Object oriented programming is one of the most popular methodologies in software
development. It offers a powerful model for creating computer programs. It speeds the
program development process, improves maintenance and enhances reusability of programs.
3) Explain what is an object?
An object is a combination of messages and data. Objects can receive and send messages and
use messages to interact with each other. The messages contain information that is to be
passed to the recipient object.
4) Explain the implementation phase with respect to OOP?
The design phase is followed by OOP, which is the implementation phase. OOP provides
specifications for writing programs in a programming language. During the implementation
phase, programming is done as per the requirements gathered during the analysis and design
phases.
5) Explain about the Design Phase?
In the design phase, the developers of the system document their understanding of the
system. Design generates the blue print of the system that is to be implemented. The first
step in creating an object oriented design is the identification of classes and their
relationships.
6) Explain about a class?
Class describes the nature of a particular thing. Structure and modularity is provided by a
Class in object oriented programming environment. Characteristics of the class should be
understandable by an ordinary non programmer and it should also convey the meaning of the
problem statement to him. Class acts like a blue print.

7) Explain about instance in object oriented programming?


Every class and an object have an instance. Instance of a particular object is created at
runtime. Values defined for a particular object define its State. Instance of an object explains
the relation ship between different elements.
8) Explain about inheritance?
Inheritance revolves around the concept of inheriting knowledge and class attributes from the
parent class. In general sense a sub class tries to acquire characteristics from a parent class
and they can also have their own characteristics. Inheritance forms an important concept in
object oriented programming.
9) Explain about multiple inheritance?
Inheritance involves inheriting characteristics from its parents also they can have their own
characteristics. In multiple inheritance a class can have characteristics from multiple parents
or classes. A sub class can have characteristics from multiple parents and still can have its
own characteristics.
10) Explain about encapsulation?
Encapsulation passes the message without revealing the exact functional details of the class.
It allows only the relevant information to the user without revealing the functional mechanism
through which a particular class had functioned.
11) Explain about abstraction?
Abstraction simplifies a complex problem to a simpler problem by specifying and modeling the
class to the relevant problem scenario. It simplifies the problem by giving the class its specific
class of inheritance. Composition also helps in solving the problem to an extent.
12) Explain the mechanism of composition?
Composition helps to simplify a complex problem into an easier problem. It makes different
classes and objects to interact with each other thus making the problem to be solved
automatically. It interacts with the problem by making different classes and objects to send a
message to each other.
13) Explain about polymorphism?
Polymorphism helps a sub class to behave like a parent class. When an object belonging to
different data types respond to methods which have a same name, the only condition being
that those methods should perform different function.
14) Explain about overriding polymorphism?
Overriding polymorphism is known to occur when a data type can perform different functions.
For example an addition operator can perform different functions such as addition, float
addition etc. Overriding polymorphism is generally used in complex projects where the use of
a parameter is more.
15) Explain about object oriented databases?
Object oriented databases are very popular such as relational database management systems.
Object oriented databases systems use specific structure through which they extract data and
they combine the data for a specific output. These DBMS use object oriented languages to
make the process easier.
16) Explain about parametric polymorphism?
Parametric polymorphism is supported by many object oriented languages and they are very
important for object oriented techniques. In parametric polymorphism code is written without
any specification for the type of data present. Hence it can be used any number of times.
17) What are all the languages which support OOP?
There are several programming languages which are implementing OOP because of its close
proximity to solve real life problems. Languages such as Python, Ruby, Ruby on rails, Perl,
PHP, Coldfusion, etc use OOP. Still many languages prefer to use DOM based languages due to
the ease in coding.

---------

1) Explain what is object oriented programming language?


Object oriented programming language allows concepts such as modularity, encapsulation,
polymorphism and inheritance. Simula is credited to be the first object oriented language.
Objects are said to be the most important part of object oriented language. Concept revolves
around making simulation programs around an object.
2) Name some languages which have object oriented language and characteristics?
Some of the languages which have object oriented languages present in them are ABAP, ECMA
Script, C++, Perl, LISP, C#, Tcl, VB, Ruby, Python, PHP, etc. Popularity of these languages
has increased considerably as they can solve complex problems with ease.
3) Explain about UML?
UML or unified modeling language is regarded to implement complete specifications and
features of object oriented language. Abstract design can be implemented in object oriented
programming languages. It lacks implementation of polymorphism on message arguments
which is a OOPs feature.
4) Explain the meaning of object in object oriented programming?
Languages which are called as object oriented almost implement everything in them as objects
such as punctuations, characters, prototypes, classes, modules, blocks, etc. They were
designed to facilitate and implement object oriented methods.
5) Explain about message passing in object oriented programming?
Message passing is a method by which an object sends data to another object or requests
other object to invoke method. This is also known as interfacing. It acts like a messenger from
one object to other object to convey specific instructions.
6) State about Java and its relation to Object oriented programming?
Java is widely used and its share is increasing considerably which is partly due to its close
resemblance to object oriented languages such as C and C++. Code written in Java can be
transported to many different platforms without changing it. It implements virtual machine.
7) What are the problems faced by the developer using object oriented programming
language?
These are some of the problems faced by the developer using object oriented language they
are: -
1) Object oriented uses design patterns which can be referred to as anything in general.
2) Repeatable solution to a problem can cause concern and disagreements and it is one of the
major problems in software design.
8) State some of the advantages of object oriented programming?
Some of the advantages of object oriented programming are as follows: -
1) A clear modular structure can be obtained which can be used as a prototype and it will not
reveal the mechanism behind the design. It does have a clear interface.
2) Ease of maintenance and modification to the existing objects can be done with ease.
3) A good framework is provided which facilitates in creating rich GUI applications.
9) Explain about inheritance in OOPS?
Objects in one class can acquire properties of the objects in other classes by way of
inheritance. Reusability which is a major factor is provided in object oriented programming
which adds features to a class without modifying it. New class can be obtained from a class
which is already present.
10) Explain about the relationship between object oriented programming and databases?
Object oriented programming and relational database programming are almost similar in
software engineering. RDBMS will not store objects directly and that’s where object oriented
programming comes into play. Object relational mapping is one such solution.
11) Explain about a class in OOP?
In Object oriented programming usage of class often occurs. A class defines the characteristics
of an object and its behaviors. This defines the nature and functioning of a specified object to
which it is assigned. Code for a class should be encapsulated.

12) Explain the usage of encapsulation?


Encapsulation specifies the different classes which can use the members of an object. The
main goal of encapsulation is to provide an interface to clients which decrease the dependency
on those features and parts which are likely to change in future. This facilitates easy changes
to the code and features.
13) Explain about abstraction?
Abstraction can also be achieved through composition. It solves a complex problem by
defining only those classes which are relevant to the problem and not involving the whole
complex code into play.
14) Explain what a method is?
A method will affect only a particular object to which it is specified. Methods are verbs
meaning they define actions which a particular object will perform. It also defines various
other characteristics of a particular object.
15) Name the different Creational patterns in OO design?
There are three patterns of design out of which Creational patterns play an important role the
various patterns described underneath this are: -
1) Factory pattern
2) Single ton pattern
3) Prototype pattern
4) Abstract factory pattern
5) Builder pattern
16) Explain about realistic modeling?
As we live in a world of objects, it logically follows that the object oriented approach models
the real world accurately. The object oriented approach allows you to identify entities as
objects having attributes and behavior.
17) Explain about the analysis phase?
The anlaysis or the object oriented analysis phase considers the system as a solution to a
problem in its environment or domain. Developer concentrates on obtaining as much
information as possible about the problem. Critical requirements needs to be identified.

C++ code examples for job interviews

Q: Write a short code using C++ to print out all odd number from 1 to 100 using a
for loop(Asked by Intacct.com people)

for( unsigned int i = 1; i < = 100; i++ )


if( i & 0x00000001 )
cout << i<<\",\";

ISO layers and what layer is the IP operated from?( Asked by Cisco system people)

cation, Presentation, Session, Transport, Network, Data link and Physical. The IP is operated in
the Network layer.

3.Q: Write a program that ask for user input from 5 to 9 then calculate the
average( Asked by Cisco system people)

A.int main()
{
int MAX=4;
int total =0;
int average=0;
int numb;
cout<<"Please enter your input from 5 to 9";
cin>>numb;
if((numb <5)&&(numb>9))
cout<<"please re type your input";
else
for(i=0;i<=MAX; i++)
{
total = total + numb;
average= total /MAX;
}
cout<<"The average number is"<<average<<endl;

return 0;
}

4.Q: Can you be bale to identify between Straight- through and Cross- over cable
wiring? and in what case do you use Straight- through and Cross-over? (Asked by
Cisco system people)

A. Straight-through is type of wiring that is one to to one connection Cross- over is type of
wiring which those wires are got switched

We use Straight-through cable when we connect between NIC Adapter and Hub. Using Cross-
over cable when connect between two NIC Adapters or sometime between two hubs.

5.Q: If you hear the CPU fan is running and the monitor power is still on, but you did
not see any thing show up in the monitor screen. What would you do to find out
what is going wrong? (Asked by WNI people)

A. I would use the ping command to check whether the machine is still alive(connect to the
network) or it is dead.

^Back to Top

C++ object-oriented interview questions


1. How do you write a function that can reverse a linked-list? (Cisco System)

void reverselist(void)
{
if(head==0)
return;
if(head->next==0)
return;
if(head->next==tail)
{
head->next = 0;
tail->next = head;
}
else
{
node* pre = head;
node* cur = head->next;
node* curnext = cur->next;
head->next = 0;
cur->next = head;
for(; curnext!=0; )
{
cur->next = pre;
pre = cur;
cur = curnext;
curnext = curnext->next;
}
curnext->next = cur;
}
}

2. What is polymorphism?

Polymorphism is the idea that a base class can be inherited by several classes. A base class
pointer can point to its child class and a base class array can store different child class objects.

3. How do you find out if a linked-list has an end? (i.e. the list is not a cycle)

You can find out by using 2 pointers. One of them goes 2 nodes each time. The second one
goes at 1 nodes each time. If there is a cycle, the one that goes 2 nodes each time will
eventually meet the one that goes slower. If that is the case, then you will know the linked-list
is a cycle.

4. How can you tell what shell you are running on UNIX system?

You can do the Echo $RANDOM. It will return a undefined variable if you are from the C-Shell,
just a return prompt if you are from the Bourne shell, and a 5 digit random numbers if you are
from the Korn shell. You could also do a ps -l and look for the shell with the highest PID.

5. What is Boyce Codd Normal form?

A relation schema R is in BCNF with respect to a set F of functional dependencies if for all
functional dependencies in F+ of the form a->b, where a and b is a subset of R, at least one of
the following holds:
• a->b is a trivial functional dependency (b is a subset of a)
• a is a superkey for schema R

^Back to Top

Interview questions on C/C++

A reader submitted the interview questions he was asked. More C/C++ questions will be
added here, as people keep sending us a set of 2-3 questions they got on their job itnerview.

Q1: Tell how to check whether a linked list is circular.

A: Create two pointers, each set to the start of the list. Update each as follows:

while (pointer1) {
pointer1 = pointer1->next;
pointer2 = pointer2->next; if (pointer2) pointer2=pointer2->next;
if (pointer1 == pointer2) {
print (\"circular\n\");
}
}
Q2: OK, why does this work?

If a list is circular, at some point pointer2 will wrap around and be either at the item just
before pointer1, or the item before that. Either way, it’s either 1 or 2 jumps until they meet.

How can you quickly find the number of elements stored in a a) static array b) dynamic
array ?

Why is it difficult to store linked list in an array?

How can you find the nodes with repetetive data in a linked list?

Write a prog to accept a given string in any order and flash error if any of the
character is different. For example : If abc is the input then abc, bca, cba, cab bac are
acceptable but aac or bcd are unacceptable.

This is a C question that I had for an intern position at Microsoft: Write out a function
that prints out all the permutations of a string. For example, abc would give you abc, acb, bac,
bca, cab, cba. You can assume that all the characters will be unique. After I wrote out my
function, he asked me to figure out from the code how many times the printf statement is run,
and also questions on optimizing my algorithm.

What’s the output of the following program? Why?

#include <stdio.h>
main()
{
typedef union
{
int a;
char b[10];
float c;
}
Union;

Union x,y = {100};


x.a = 50;
strcpy(x.b,\"hello\");
x.c = 21.50;

printf(\"Union x : %d %s %f \n\",x.a,x.b,x.c );
printf(\"Union y :%d %s%f \n\",y.a,y.b,y.c);
}

Given inputs X, Y, Z and operations | and & (meaning bitwise OR and AND, respectively)

What is output equal to in

output = (X & Y) | (X & Z) | (Y & Z)

^Back to Top

C++ gamedev interview questions

This set of questions came from a prominent gaming company. As you can see, the answers
are not given (the interviews are typically conducted by senior developers), but there’s a set
of notes with common mistakes to avoid.

1. Explain which of the following declarations will compile and what will be
constant - a pointer or the value pointed at:
o const char *
o char const *
o char * const

Note: Ask the candidate whether the first declaration is pointing to a string or a single
character. Both explanations are correct, but if he says that it’s a single character pointer, ask
why a whole string is initialized as char* in C++. If he says this is a string declaration, ask
him to declare a pointer to a single character. Competent candidates should not have
problems pointing out why const char* can be both a character and a string declaration,
incompetent ones will come up with invalid reasons.

2. You’re given a simple code for the class BankCustomer. Write the following
functions:
o Copy constructor
o = operator overload
o == operator overload
o + operator overload (customers’ balances should be added up, as an example
of joint account between husband and wife)

Note:Anyone confusing assignment and equality operators should be dismissed from the
interview. The applicant might make a mistake of passing by value, not by reference. The
candidate might also want to return a pointer, not a new object, from the addition operator.
Slightly hint that you’d like the value to be changed outside the function, too, in the first case.
Ask him whether the statement customer3 = customer1 + customer2 would work in the
second case.

3. What problems might the following macro bring to the application?

#define sq(x) x*x

4. Consider the following struct declarations:


5. struct A { A(){ cout << \"A\"; } };
6. struct B { B(){ cout << \"B\"; } };
7. struct C { C(){ cout << \"C\"; } };
8. struct D { D(){ cout << \"D\"; } };
9. struct E : D { E(){ cout << \"E\"; } };
10. struct F : A, B
11. {
12. C c;
13. D d;
14. E e;
15. F() : B(), A(),d(),c(),e() { cout << \"F\"; }
};

What constructors will be called when an instance of F is initialized? Produce the program
output when this happens.

16. Anything wrong with this code?


17. T *p = new T[10];
18. delete p;

Note: Incorrect replies: “No, everything is correct”, “Only the first element of the array will be
deleted”, “The entire array will be deleted, but only the first element destructor will be called”.

19. Anything wrong with this code?


20. T *p = 0;
21. delete p;

Note: Typical wrong answer: Yes, the program will crash in an attempt to delete a null pointer.
The candidate does not understand pointers. A very smart candidate will ask whether delete
is overloaded for the class T.

22. Explain virtual inheritance. Draw the diagram explaining the initialization of
the base class when virtual inheritance is used.
Note: Typical mistake for applicant is to draw an inheritance diagram, where a single
base class is inherited with virtual methods. Explain to the candidate that this is not
virtual inheritance. Ask them for the classic definition of virtual inheritance. Such
question might be too complex for a beginning or even intermediate developer, but
any applicant with advanced C++ experience should be somewhat familiar with the
concept, even though he’ll probably say he’d avoid using it in a real project. Moreover,
even the experienced developers, who know about virtual inheritance, cannot
coherently explain the initialization process. If you find a candidate that knows both
the concept and the initialization process well, he’s hired.
23. What’s potentially wrong with the following code?
24.
25. long value;
26. //some stuff
27. value &= 0xFFFF;

Note: Hint to the candidate about the base platform they’re developing for. If the person still
doesn’t find anything wrong with the code, they are not experienced with C++.

28. What does the following code do and why would anyone write something like
that?
29. void send (int *to, int * from, int count)
30. {
31. int n = (count + 7) / 8;
32. switch ( count % 8)
33. {
34. case 0: do { *to++ = *from++;
35. case 7: *to++ = *from++;
36. case 6: *to++ = *from++;
37. case 5: *to++ = *from++;
38. case 4: *to++ = *from++;
39. case 3: *to++ = *from++;
40. case 2: *to++ = *from++;
41. case 1: *to++ = *from++;
42. } while ( --n > 0 );
43. }
44. }
45. In the H file you see the following declaration:
46. class Foo {
47. void Bar( void ) const ;
48. };

Tell me all you know about the Bar() function.

Top 10 list of advantages of C++ over C.


1: Stronger Type Checking - the use of classes, inheritance &amp;
automatic type
conversions mostly eliminates the need for the abominable void* of C.

2: Type safe linkage - you can't accidentally call a routine from


another
module with the
wrong type and/or number of arguments - even if your header files get
out of
date.

3: A complex data type is provided. It includes all the standard


arithmetic
operations, implemented as operators, not function calls.

4: User-defined operators and function overloading are supported.


When you
design a data type you can specify which operators &amp; functions are
provided.

5: You can use class libraries to provide robust new data types which
can be
made exceptionally easy to use.
For example, the Rogue Wave 'math.h++' class library implements general
multi-dimensional arrays which can be manipulated with high-level
operations
and an intuitive syntax:

DComplexArray a(10,10); // Construct a 10x10 complex array


cin >> a; // read it in from standard input
DComplexArray b = inverse(a); // Calculate the inverse
cout << b; // write out the inverse
cout << variance(b.diagonal()); // write out the variance of the
diagonal
elements of b

6: You can define automatic type conversions to convert between data


types.
For example, the Rogue Wave library provides a conversion from a double
array
to a complex array.

DoubleVec a(10, 0.0, 1.0); // Construct a double vector in initialised


to
{0,1,2,3,4...
DComplexVec z = a; // Construct a complex vector initialised to
{(0,0),(1,0),(2,0),...
cout << a; // write them out
cout << z;
cout << cos(z)*exp(DComplex(0,1)*a);

7: Provides inline functions which combine the efficiency of using


macros
with the safety of using functions - simply prepend the word 'inline' in
front of the function - if the compiler can inline it, it will.

inline Double
SumOfPositiveElements
(const DoubleVec&amp; v)
{
Double theSum = 0;
for (int i = 0; i < v.length(); i++) {
if (v[i] > 0) {
theSum += v[i];
}
}
return theSum;
}

8: C++ Compiles most ANSI C code directly and can call compiled C code
directly, so you don't even have to learn anything new at all!
I recently spent some time converting a copy of SUPER to ANSI C on a
Macintosh and was able to compile it equally easily with C++ as well.
The
C++ version also had the advantage that it worked when I finished, I had
managed to break the C version so that it crashed almost immediately.

9: You don't have to put all of your declarations at the top of each
block
in C++. This means
that you can organise your code into logically related 'paragraphs'
complete
with their necessary declarations. This makes code much more
maintainable -
you can easily move sections of code around, taking the necessary
declarations along at the same time. If you use the const modifier you
can
also ensure that variables whose value should not change after it is
first
calculated do not do so.

Double x,y; // Declare two variables


cin >> x >> y; // read in their values
const Double sqrtX = sqrt(x); // Calculate the square roots
const Double sqrtY = sqrt(y);
cout << sqrt(sqrtX+sqrtY);
sqrtX = 42; // Will give an error...

10: Classes provide extensible types, promoting code reuse. This can
result in major savings in the amount of code written. I saw a recent
article which stated that the new Taligent operating system, which is
written
in C++, consists of 250,000 lines of code, whereas WindowsNT, written
in C,
was said to consist of 4,000,000 lines of code.

The unexpected() function (C++ only)

When a function with an exception specification throws an exception that is not listed in its exception
specification, the C++ run time does the following:

1. The unexpected() function is called.


2. The unexpected() function calls the function pointed to by unexpected_handler. By
default, unexpected_handler points to the function terminate().

You can replace the default value of unexpected_handler with the function set_unexpected().

Although unexpected() cannot return, it may throw (or rethrow) an exception. Suppose the
exception specification of a function f() has been violated. If unexpected() throws an exception
allowed by the exception specification of f(), then the C++ run time will search for another handler at
the call of f(). The following example demonstrates this:

#include <iostream>
using namespace std;

struct E {
const char* message;
E(const char* arg) : message(arg) { }
};

void my_unexpected() {
cout << "Call to my_unexpected" << endl;
throw E("Exception thrown from my_unexpected");
}
void f() throw(E) {
cout << "In function f(), throw const char* object" << endl;
throw("Exception, type const char*, thrown from f()");
}

int main() {
set_unexpected(my_unexpected);
try {
f();
}
catch (E& e) {
cout << "Exception in main(): " << e.message << endl;
}
}

The following is the output of the above example:

In function f(), throw const char* object


Call to my_unexpected
Exception in main(): Exception thrown from my_unexpected

The main() function's try block calls function f(). Function f() throws an object of type const
char*. However the exception specification of f() allows only objects of type E to be thrown. The
function unexpected() is called. The function unexpected() calls my_unexpected(). The
function my_unexpected() throws an object of type E. Since unexpected() throws an object
allowed by the exception specification of f(), the handler in the main() function may handle the
exception.

If unexpected() did not throw (or rethrow) an object allowed by the exception specification of f(),
then the C++ run time does one of two things:

• If the exception specification of f() included the class std::bad_exception,


unexpected() will throw an object of type std::bad_exception, and the C++ run time
will search for another handler at the call of f().
• If the exception specification of f() did not include the class std::bad_exception, the
function terminate() is called.

The set_unexpected() and set_terminate() functions (C++ only)

The function unexpected(), when invoked, calls the function most recently supplied as an argument
to set_unexpected(). If set_unexpected() has not yet been called, unexpected() calls
terminate().

The function terminate(), when invoked, calls the function most recently supplied as an argument
to set_terminate(). If set_terminate() has not yet been called, terminate() calls abort(),
which ends the program.

You can use set_unexpected() and set_terminate() to register functions you define to be
called by unexpected() and terminate(). The functions set_unexpected() and
set_terminate() are included in the standard header files. Each of these functions has as its return
type and its argument type a pointer to function with a void return type and no arguments. The pointer
to function you supply as the argument becomes the function called by the corresponding special
function: the argument to set_unexpected() becomes the function called by unexpected(), and
the argument to set_terminate() becomes the function called by terminate().

Both set_unexpected() and set_terminate() return a pointer to the function that was
previously called by their respective special functions (unexpected() and terminate()). By saving
the return values, you can restore the original special functions later so that unexpected() and
terminate() will once again call terminate() and abort().

If you use set_terminate() to register your own function, the function should no return to its caller
but terminate execution of the program.

Stack unwinding (C++ only)

When an exception is thrown and control passes from a try block to a handler, the C++ run time calls
destructors for all automatic objects constructed since the beginning of the try block. This process is
called stack unwinding. The automatic objects are destroyed in reverse order of their construction.
(Automatic objects are local objects that have been declared auto or register, or not declared
static or extern. An automatic object x is deleted whenever the program exits the block in which x
is declared.)

If an exception is thrown during construction of an object consisting of subobjects or array elements,


destructors are only called for those subobjects or array elements successfully constructed before the
exception was thrown. A destructor for a local static object will only be called if the object was
successfully constructed.

If during stack unwinding a destructor throws an exception and that exception is not handled, the
terminate() function is called. The following example demonstrates this:

#include <iostream>
using namespace std;

struct E {
const char* message;
E(const char* arg) : message(arg) { }
};

void my_terminate() {
cout << "Call to my_terminate" << endl;
};

struct A {
A() { cout << "In constructor of A" << endl; }
~A() {
cout << "In destructor of A" << endl;
throw E("Exception thrown in ~A()");
}
};

struct B {
B() { cout << "In constructor of B" << endl; }
~B() { cout << "In destructor of B" << endl; }
};

int main() {
set_terminate(my_terminate);

try {
cout << "In try block" << endl;
A a;
B b;
throw("Exception thrown in try block of main()");
}
catch (const char* e) {
cout << "Exception: " << e << endl;
}
catch (...) {
cout << "Some exception caught in main()" << endl;
}

cout << "Resume execution of main()" << endl;


}

The following is the output of the above example:

In try block
In constructor of A
In constructor of B
In destructor of B
In destructor of A
Call to my_terminate

In the try block, two automatic objects are created: a and b. The try block throws an exception of type
const char*. The handler catch (const char* e) catches this exception. The C++ run time
unwinds the stack, calling the destructors for a and b in reverse order of their construction. The
destructor for a throws an exception. Since there is no handler in the program that can handle this
exception, the C++ run time calls terminate(). (The function terminate() calls the function
specified as the argument to set_terminate(). In this example, terminate() has been specified
to call my_terminate().)

Overloading class member access (C++ only)

You overload operator-> with a nonstatic member function that has no parameters. The following
example demonstrates how the compiler interprets overloaded class member access operators:

struct Y {
void f() { };
};

struct X {
Y* ptr;
Y* operator->() {
return ptr;
};
};
int main() {
X x;
x->f();
}

The statement x->f() is interpreted as (x.operator->())->f().

The operator-> is used (often in conjunction with the pointer-dereference operator) to implement
"smart pointers." These pointers are objects that behave like normal pointers except they perform
other tasks when you access an object through them, such as automatic object deletion (either when
the pointer is destroyed, or the pointer is used to point to another object), or reference counting
(counting the number of smart pointers that point to the same object, then automatically deleting the
object when that count reaches zero).

One example of a smart pointer is included in the C++ Standard Library called auto_ptr. You can
find it in the <memory> header. The auto_ptr class implements automatic object deletion.

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.

The using declaration and namespaces (C++ only)

A using declaration provides access to a specific namespace member. This is accomplished by


applying the using keyword to a namespace name with its corresponding namespace member.

Using declaration syntax

>>-using--namespace--::--member--------------------------------><

In this syntax diagram, the qualifier name follows the using declaration and the member follows the
qualifier name. For the declaration to work, the member must be declared inside the given
namespace. For example:

namespace A {
int i;
int k;
void f;
void g;
}

using A::k

In this example, the using declaration is followed by A, the name of namespace A, which is then
followed by the scope operator (::), and k. This format allows k to be accessed outside of namespace
A through a using declaration. After issuing a using declaration, any extension made to that specific
namespace will not be known at the point at which the using declaration occurs.
Overloaded versions of a given function must be included in the namespace prior to that given
function's declaration. A using declaration may appear at namespace, block and class scope.

The using declaration and class members (C++ only)

A using declaration in a definition of a class A allows you to introduce a name of a data member or
member function from a base class of A into the scope of A.

You would need a using declaration in a class definition if you want to create a set of overload a
member functions from base and derived classes, or you want to change the access of a class
member.

using declaration syntax

>>-using--+-+----------+--+----+--nested_name_specifier--unqualified_id--;-
+-><
| '-typename-' '-::-'
|
'-::--
unqualified_id--;------------------------------------------'

A using declaration in a class A may name one of the following:

• A member of a base class of A


• A member of an anonymous union that is a member of a base class of A
• An enumerator for an enumeration type that is a member of a base class of A

The following example demonstrates this:

struct Z {
int g();
};

struct A {
void f();
enum E { e };
union { int u; };
};

struct B : A {
using A::f;
using A::e;
using A::u;
// using Z::g;
};

The compiler would not allow the using declaration using Z::g because Z is not a base class of A.

A using declaration cannot name a template. For example, the compiler will not allow the following:

struct A {
template<class T> void f(T);
};
struct B : A {
using A::f<int>;
};

Every instance of the name mentioned in a using declaration must be accessible. The following
example demonstrates this:

struct A {
private:
void f(int);
public:
int f();
protected:
void g();
};

struct B : A {
// using A::f;
using A::g;
};

The compiler would not allow the using declaration using A::f because void A::f(int) is not
accessible from B even though int A::f() is accessible.

Overloading unary operators (C++ only)

You overload a unary operator with either a nonstatic member function that has no parameters, or a
nonmember function that has one parameter. Suppose a unary operator @ is called with the statement
@t, where t is an object of type T. A nonstatic member function that overloads this operator would
have the following form:

return_type operator@()

A nonmember function that overloads the same operator would have the following form:

return_type operator@(T)

An overloaded unary operator may return any type.

The following example overloads the ! operator:

#include <iostream>
using namespace std;

struct X { };

void operator!(X) {
cout << "void operator!(X)" << endl;
}

struct Y {
void operator!() {
cout << "void Y::operator!()" << endl;
}
};

struct Z { };

int main() {
X ox; Y oy; Z oz;
!ox;
!oy;
// !oz;
}

The following is the output of the above example:

void operator!(X)
void Y::operator!()
The operator function call !ox is interpreted as operator!(X). The call !oy is interpreted as
Y::operator!().

(The compiler would not allow !oz because the ! operator has not been defined for class Z.)

When To Use Goto When Programming in C


Although the use of goto is almost always bad programming practice (surely you can find a better
way of doing XYZ), there are times when it really isn't a bad choice. Some might even argue that,
when it is useful, it's the best choice.

Most of what I have to say about goto really only applies to C. If you're using C++, there's no
sound reason to use goto in place of exceptions. In C, however, you don't have the power of an
exception handling mechanism, so if you want to separate out error handling from the rest of your
program logic, and you want to avoid rewriting clean up code multiple times throughout your code,
then goto can be a good choice.

What do I mean? You might have some code that looks like this:

int big_function()
{
/* do some work */
if([error])
{
/* clean up*/
return [error];
}
/* do some more work */
if([error])
{
/* clean up*/
return [error];
}
/* do some more work */
if([error])
{
/* clean up*/
return [error];
}
/* do some more work */
if([error])
{
/* clean up*/
return [error];
}
/* clean up*/
return [success];
}
This is fine until you realize that you need to change your cleanup code. Then you have to go
through and make 4 changes. Now, you might decide that you can just encapsulate all of the
cleanup into a single function; that's not a bad idea. But it does mean that you'll need to be careful
with pointers -- if you plan to free a pointer in your cleanup function, there's no way to set it to then
point to NULL unless you pass in a pointer to a pointer. In a lot of cases, you won't be using that
pointer again anyway, so that may not be a major concern. On the other hand, if you add in a new
pointer, file handle, or other thing that needs cleanup, then you'll need to change your cleanup
function again; and then you'll need to change the arguments to that function.

In some cases, this might be acceptable -- but if you're making a lot of changes to your code,
adding in new variables, etc. -- it may not be worth the time or the extra lines of code to make that
function call.

Instead, since you know that you're going to be executing only one piece of code and then returning
from the function, you might as well use a goto to jump to the very end of the function, where you
have your cleanup code.

Goto is a pretty simple keyword: you just need to include a "label" placed above the target location
(followed by a colon), and then direct the program to go to the label. Note that this only works
within the same function; you can't just enter one function from another.
goto label;
/* Code
...
*/
label:
Now, using this, if we want to handle all our errors in one place, we'll need to add in a variable to
track the return value of our function so we can return it:
int big_function()
{
int ret_val = [success];
/* do some work */
if([error])
{
ret_val = [error];
goto end;
}
/* do some more work */
if([error])
{
ret_val = [error];
goto end;
}
/* do some more work */
if([error])
{
ret_val = [error];
goto end;
}
/* do some more work */
if([error])
{
ret_val = [error];
goto end;
}
end:
/* clean up*/
return ret_val;
}
The benefit here is that your code following end has access to everything it will need to perform
cleanup, and you've managed to reduce the number of change points considerably. Another benefit
is that you've gone from having multiple exit points for your function to just one; there's no chance
you'll accidentally return from the function without cleaning up.

Moreover, since goto is only being used to jump to a single point, it's not as though you're creating
a mass of spaghetti code jumping back and forth in an attempt to simulate function calls. Rather,
goto actually helps write more structured code.

There is one thing to be aware of: while your cleanup code should be able to free all of the memory
you use, there may be times when you actually want to free that memory yourself and possibly
reallocate it later. In these cases, if you do call free on a ptr and then have an if([error]) between
that call to free and the subsequent call to malloc, you should definitely set the pointer to point to
NULL! This will prevent your jumping to the cleanup code and then calling free on that pointer a
second time, which can result in a security hole (the "double free" problem).

Goto should always be used sparingly, and as a last resort -- but there is a time and a place for it.
The question should be not "do you have to use it" but "is it the best choice" to use it.

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*)
}

The this pointer (C++ only)

The keyword this identifies a special type of pointer. Suppose that you create an object named x of
class A, and class A has a nonstatic member function f(). If you call the function x.f(), the keyword
this in the body of f() stores the address of x. You cannot declare the this pointer or make
assignments to it.

A static member function does not have a this pointer.

The type of the this pointer for a member function of a class type X, is X* const. If the member
function is declared with the const qualifier, the type of the this pointer for that member function for
class X, is const X* const.

A const this pointer can by used only with const member functions. Data members of the class
will be constant within that function. The function is still able to change the value, but requires a
const_cast to do so:

void foo::p() const{


member = 1; // illegal
const_cast <int&> (member) = 1; // a bad practice but legal
}

A better technique would be to declare member mutable.

If the member function is declared with the volatile qualifier, the type of the this pointer for that
member function for class X is volatile X* const. For example, the compiler will not allow the
following:

struct A {
int a;
int f() const { return a++; }
};

The compiler will not allow the statement a++ in the body of function f(). In the function f(), the
this pointer is of type A* const. The function f() is trying to modify part of the object to which
this points.

The this pointer is passed as a hidden argument to all nonstatic member function calls and is
available as a local variable within the body of all nonstatic functions.

For example, you can refer to the particular class object that a member function is called for by using
the this pointer in the body of the member function. The following code example produces the output
a = 5:

#include <iostream>
using namespace std;

struct X {
private:
int a;
public:
void Set_a(int a) {

// The 'this' pointer is used to retrieve 'xobj.a'


// hidden by the automatic variable 'a'
this->a = a;
}
void Print_a() { cout << "a = " << a << endl; }
};

int main() {
X xobj;
int a = 5;
xobj.Set_a(a);
xobj.Print_a();
}

In the member function Set_a(), the statement this->a = a uses the this pointer to retrieve
xobj.a hidden by the automatic variable a.

Unless a class member name is hidden, using the class member name is equivalent to using the class
member name with the this pointer and the class member access operator (->).
The example in the first column of the following table shows code that uses class members without the
this pointer. The code in the second column uses the variable THIS to simulate the first column's
hidden use of the this pointer:

Code without using this pointer Equivalent code, the THIS variable simulating the hidden use of the this pointer

#include <string> #include <string>


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

struct X { struct X {
private: private:
int len; int len;
char *ptr; char *ptr;
public: public:
int GetLen() { int GetLen (X* const THIS) {
return len; return THIS->len;
} }
char * GetPtr() { char * GetPtr (X* const THIS) {
return ptr; return THIS->ptr;
} }
X& Set(char *); X& Set(X* const, char *);
X& Cat(char *); X& Cat(X* const, char *);
X& Copy(X&); X& Copy(X* const, X&);
void Print(); void Print(X* const);
}; };

X& X::Set(char *pc) { X& X::Set(X* const THIS, char *pc) {


len = strlen(pc); THIS->len = strlen(pc);
ptr = new char[len]; THIS->ptr = new char[THIS->len];
strcpy(ptr, pc); strcpy(THIS->ptr, pc);
return *this; return *THIS;
} }

X& X::Cat(char *pc) { X& X::Cat(X* const THIS, char *pc) {


len += strlen(pc); THIS->len += strlen(pc);
strcat(ptr,pc); strcat(THIS->ptr, pc);
return *this; return *THIS;
} }

X& X::Copy(X& x) { X& X::Copy(X* const THIS, X& x) {


Set(x.GetPtr()); THIS->Set(THIS, x.GetPtr(&x));
return *this; return *THIS;
} }

void X::Print() { void X::Print(X* const THIS) {


cout << ptr << endl; cout << THIS->ptr << endl;
} }

int main() { int main() {


X xobj1; X xobj1;
xobj1.Set("abcd") xobj1.Set(&xobj1 , "abcd")
.Cat("efgh"); .Cat(&xobj1 , "efgh");

xobj1.Print(); xobj1.Print(&xobj1);
X xobj2; X xobj2;
xobj2.Copy(xobj1) xobj2.Copy(&xobj2 , xobj1)
.Cat("ijkl"); .Cat(&xobj2 , "ijkl");

xobj2.Print(); xobj2.Print(&xobj2);
} }

Both examples produce the following output:

abcdefgh
abcdefghijkl

Copy constructors (C++ only)


The copy constructor lets you create a new object from an existing one by initialization. A copy
constructor of a class A is a non-template constructor in which the first parameter is of type A&, const
A&, volatile A&, or const volatile A&, and the rest of its parameters (if there are any) have
default values.

If you do not declare a copy constructor for a class A, the compiler will implicitly declare one for you,
which will be an inline public member.

The following example demonstrates implicitly defined and user-defined copy constructors:

#include <iostream>
using namespace std;

struct A {
int i;
A() : i(10) { }
};

struct B {
int j;
B() : j(20) {
cout << "Constructor B(), j = " << j << endl;
}

B(B& arg) : j(arg.j) {


cout << "Copy constructor B(B&), j = " << j << endl;
}

B(const B&, int val = 30) : j(val) {


cout << "Copy constructor B(const B&, int), j = " << j << endl;
}
};

struct C {
C() { }
C(C&) { }
};

int main() {
A a;
A a1(a);
B b;
const B b_const;
B b1(b);
B b2(b_const);
const C c_const;
// C c1(c_const);
}

The following is the output of the above example:

Constructor B(), j = 20
Constructor B(), j = 20
Copy constructor B(B&), j = 20
Copy constructor B(const B&, int), j = 30
The statement A a1(a) creates a new object from a with an implicitly defined copy constructor. The
statement B b1(b) creates a new object from b with the user-defined copy constructor B::B(B&).
The statement B b2(b_const) creates a new object with the copy constructor B::B(const B&,
int). The compiler would not allow the statement C c1(c_const) because a copy constructor that
takes as its first parameter an object of type const C& has not been defined.

The implicitly declared copy constructor of a class A will have the form A::A(const A&) if the
following are true:

• The direct and virtual bases of A have copy constructors whose first parameters have been
qualified with const or const volatile
• The nonstatic class type or array of class type data members of A have copy constructors
whose first parameters have been qualified with const or const volatile

If the above are not true for a class A, the compiler will implicitly declare a copy constructor with the
form A::A(A&).

The compiler cannot allow a program in which the compiler must implicitly define a copy constructor for
a class A and one or more of the following are true:

• Class A has a nonstatic data member of a type which has an inaccessible or ambiguous copy
constructor.
• Class A is derived from a class which has an inaccessible or ambiguous copy constructor.

The compiler will implicitly define an implicitly declared constructor of a class A if you initialize an
object of type A or an object derived from class A.

An implicitly defined copy constructor will copy the bases and members of an object in the same order
that a constructor would initialize the bases and members of the object

Overview of constructors and destructors (C++ only)

Because classes have complicated internal structures, including data and functions, object initialization
and cleanup for classes is much more complicated than it is for simple data structures. Constructors
and destructors are special member functions of classes that are used to construct and destroy class
objects. Construction may involve memory allocation and initialization for objects. Destruction may
involve cleanup and deallocation of memory for objects.

Like other member functions, constructors and destructors are declared within a class declaration.
They can be defined inline or external to the class declaration. Constructors can have default
arguments. Unlike other member functions, constructors can have member initialization lists. The
following restrictions apply to constructors and destructors:

• Constructors and destructors do not have return types nor can they return values.
• References and pointers cannot be used on constructors and destructors because their
addresses cannot be taken.
• Constructors cannot be declared with the keyword virtual.
• Constructors and destructors cannot be declared static, const, or volatile.
• Unions cannot contain class objects that have constructors or destructors.

Constructors and destructors obey the same access rules as member functions. For example, if you
declare a constructor with protected access, only derived classes and friends can use it to create class
objects.

The compiler automatically calls constructors when defining class objects and calls destructors when
class objects go out of scope. A constructor does not allocate memory for the class object its this
pointer refers to, but may allocate storage for more objects than its class object refers to. If memory
allocation is required for objects, constructors can explicitly call the new operator. During cleanup, a
destructor may release objects allocated by the corresponding constructor. To release objects, use the
delete operator.

Derived classes do not inherit or overload constructors or destructors from their base classes, but they
do call the constructor and destructor of base classes. Destructors can be declared with the keyword
virtual.

Constructors are also called when local or temporary class objects are created, and destructors are
called when local or temporary objects go out of scope.

You can call member functions from constructors or destructors. You can call a virtual function, either
directly or indirectly, from a constructor or destructor of a class A. In this case, the function called is the
one defined in A or a base class of A, but not a function overridden in any class derived from A. This
avoids the possibility of accessing an unconstructed object from a constructor or destructor. The
following example demonstrates this:

#include <iostream>
using namespace std;

struct A {
virtual void f() { cout << "void A::f()" << endl; }
virtual void g() { cout << "void A::g()" << endl; }
virtual void h() { cout << "void A::h()" << endl; }
};

struct B : A {
virtual void f() { cout << "void B::f()" << endl; }
B() {
f();
g();
h();
}
};

struct C : B {
virtual void f() { cout << "void C::f()" << endl; }
virtual void g() { cout << "void C::g()" << endl; }
virtual void h() { cout << "void C::h()" << endl; }
};

int main() {
C obj;
}

The following is the output of the above example:


void B::f()
void A::g()
void A::h()

The constructor of B does not call any of the functions overridden in C because C has been derived
from B, although the example creates an object of type C named obj.

You can use the typeid or the dynamic_cast operator in constructors or destructors, as well as
member initializers of constructors.

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.

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.

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[]().

The main() function

When a program begins running, the system calls the function main, which marks the entry point of
the program. By default, main has the storage class extern. Every program must have one function
named main, and the following constraints apply:

• No other function in the program can be called main.


• main cannot be defined as inline or static.
• main cannot be called from within a program.
• The address of main cannot be taken.
• The main function cannot be overloaded.

The function main can be defined with or without parameters, using any of the following forms:

int main (void)


int main ( )
int main(int argc, char *argv[])
int main (int argc, char ** argv)

Although any name can be given to these parameters, they are usually referred to as argc and argv.
The first parameter, argc (argument count) is an integer that indicates how many arguments were
entered on the command line when the program was started. The second parameter, argv (argument
vector), is an array of pointers to arrays of character objects. The array objects are null-terminated
strings, representing the arguments that were entered on the command line when the program was
started.
The first element of the array, argv[0], is a pointer to the character array that contains the program
name or invocation name of the program that is being run from the command line. argv[1] indicates
the first argument passed to the program, argv[2] the second argument, and so on.

The following example program backward prints the arguments entered on a command line such that
the last argument is printed first:

#include <stdio.h>
int main(int argc, char *argv[])
{
while (--argc > 0)
printf("%s ", argv[argc]);
}

Invoking this program from a command line with the following:

backward string1 string2

gives the following output:

string2 string1

The arguments argc and argv would contain the following values:

Object Value

argc 3

argv[0] pointer to string "backward"

argv[1] pointer to string "string1"

argv[2] pointer to string "string2"

argv[3] NULL

The inline function specifier

An inline function is one for which the compiler copies the code from the function definition directly into
the code of the calling function rather than creating a separate set of instructions in memory. Instead of
transferring control to and from the function code segment, a modified copy of the function body may
be substituted directly for the function call. In this way, the performance overhead of a function call is
avoided.

Any function, with the exception of main, can be declared or defined as inline with the
inline function specifier. Static local variables are not allowed to be defined within the body of an
inline function.

C++ functions implemented inside of a class declaration are automatically defined inline.
Regular C++ functions and member functions declared outside of a class declaration, with the
exception of main, can be declared or defined as inline with the inline function specifier. Static
locals and string literals defined within the body of an inline function are treated as the same object
across translation units; see Linkage of inline functions for details.

The following code fragment shows an inline function definition:

inline int add(int i, int j) { return i + j; }

The use of the inline specifier does not change the meaning of the function. However, the inline
expansion of a function may not preserve the order of evaluation of the actual arguments.

The most efficient way to code an inline function is to place the inline function definition in a header
file, and then include the header in any file containing a call to the function which you would like to
inline.

Note:
The inline qualifier is represented by the following keywords:
• The inline keyword is only recognized under compilation with c99 or with the
-qlanglvl=stdc99 or -qlanglvl=extc99 options (or equivalent pragmas) or -qkeyword=inline.
Note that the latter option is enabled by default for xlc in the configuration file that is shipped
with the compiler. The __inline__ keyword is recognized at all language levels; however,
see Linkage of inline functions below for the semantics of this keyword.
• The inline and __inline__ keywords are recognized at all language levels.

Related information

• The always_inline function attribute


• The noinline function attribute

Linkage of inline functions


C only

In C, inline functions are treated by default as having static linkage; that is, they are only visible within
a single translation unit. Therefore, in the following example, even though function foo is defined in
exactly the same way, foo in file a.c and foo in file b.c are treated as separate functions: two
function bodies are generated, and assigned two different addresses in memory:

// a.c

#include <stdio.h>

inline int foo(){


return 3;
}

void g() {
printf("foo called from g: return value = %d, address = %p\n", foo(),
&foo);
}

// b.c

#include <stdio.h>
inline int foo(){
return 3;
}

void g();

int main() {
printf("foo called from main: return value = %d, address = %p\n", foo(),
&foo);
g();
}

The output from the compiled program is:

foo called from main: return value = 3, address = 0x10000580


foo called from g: return value = 3, address = 0x10000500

Since inline functions are treated as having internal linkage, an inline function definition can co-exist
with a regular, external definition of a function with the same name in another translation unit.
However, when you call the function from the file containing the inline definition, the compiler may
choose either the inline version defined in the same file or the external version defined in another file
for the call; your program should not rely on the inline version being called. In the following example,
the call to foo from function g could return either 6 or 3:

// a.c

#include <stdio.h>

inline int foo(){


return 6;
}

void g() {
printf("foo called from g: return value = %d\n", foo());
}

// b.c

#include <stdio.h>

int foo(){
return 3;
}

void g();

int main() {
printf("foo called from main: return value = %d\n", foo());
g();
}
Similarly, if you define a function as extern inline, or redeclare an inline function as extern,
the function simply becomes a regular, external function and is not inlined.

If you specify the __inline__ keyword, with the trailing underscores, the compiler uses the
GNU C semantics for inline functions. In contrast to the C99 semantics, a function defined as
__inline__ provides an external definition only; a function defined as static __inline__
provides an inline definition with internal linkage (as in C99); and a function defined as extern
__inline__, when compiled with optimization enabled, allows the co-existence of an inline and
external definition of the same function. For more information on the GNU C implementation of inline
functions, see the GCC documentation, available at http://gcc.gnu.org/onlinedocs/.

End of C only
C++ only

You must define an inline function in exactly the same way in each translation unit in which the
function is used or called. Furthermore, if a function is defined as inline, but never used or called
within the same translation unit, it is discarded by the compiler (unless you compile with the
-qkeepinlines option).

Nevertheless, in C++, inline functions are treated by default as having external linkage, meaning that
the program behaves as if there is only one copy of the function. The function will have the same
address in all translation units and each translation unit will share any static locals and string literals.
Therefore, compiling the previous example gives the following output:

foo called from main: return value = 3, address = 0x10000580


foo called from g: return value = 3, address = 0x10000580
Redefining an inline function with the same name but with a different function body is illegal; however,
the compiler does not flag this as an error, but simply generates a function body for the version defined
in the first file entered on the compilation command line, and discards the others.

Therefore, the following example, in which inline function foo is defined differently in two different files,
may not produce the expected results:

// a.C

#include <stdio.h>

inline int foo(){


return 6;
}

void g() {
printf("foo called from g: return value = %d, address = %p\n", foo(),
&foo);
}

// b.C

#include <stdio.h>

inline int foo(){


return 3;
}

void g();

int main() {
printf("foo called from main: return value = %d, address = %p\n", foo(),
&foo);
g();
}

When compiled with the command xlC a.C b.C, the output is:
foo called from main: return value = 6, address = 0x10001640
foo called from g: return value = 6, address = 0x10001640

The call to foo from main does not use the inline definition provided in b.C, but rather calls foo as a
regular external function defined in a.C. It is your responsibility to ensure that inline function definitions
with the same name match exactly across translation units, to avoid unexpected results.

Because inline functions are treated as having external linkage, any static local variables or string
literals that are defined within the body of an inline function are treated as the same object across
translation units. The following example demonstrates this:

// a.C

#include <stdio.h>

inline int foo(){


static int x = 23;
printf("address of x = %p\n", &x);
x++;
return x;
}

void g() {
printf("foo called from g: return value = %d\n", foo());
}

// b.C

#include <stdio.h>

inline int foo()


{
static int x=23;
printf("address of x = %p\n", &x);
x++;
return x;
}

void g();

int main() {
printf("foo called from main: return value = %d\n", foo());
g();
}

The output of this program shows that x in both definitions of foo is indeed the same object:

address of x = 0x10011d5c
foo called from main: return value = 24
address of x = 0x10011d5c
foo called from g: return value = 25

If you want to ensure that each instance of function defined as inline is treated as a separate function,
you can use the static specifier in the function definition in each translation unit, or compile with the
-qstaticinline option. Note, however, that static inline functions are removed from name lookup during
template instantiation, and are not found.
Overloading unary operators (C++ only)

You overload a unary operator with either a nonstatic member function that has no parameters, or a
nonmember function that has one parameter. Suppose a unary operator @ is called with the statement
@t, where t is an object of type T. A nonstatic member function that overloads this operator would
have the following form:

return_type operator@()

A nonmember function that overloads the same operator would have the following form:

return_type operator@(T)

An overloaded unary operator may return any type.

The following example overloads the ! operator:

#include <iostream>
using namespace std;

struct X { };

void operator!(X) {
cout << "void operator!(X)" << endl;
}

struct Y {
void operator!() {
cout << "void Y::operator!()" << endl;
}
};

struct Z { };

int main() {
X ox; Y oy; Z oz;
!ox;
!oy;
// !oz;
}

The following is the output of the above example:

void operator!(X)
void Y::operator!()
The operator function call !ox is interpreted as operator!(X). The call !oy is interpreted as
Y::operator!().

(The compiler would not allow !oz because the ! operator has not been defined for class Z.)
Overloading assignments (C++ only)

You overload the assignment operator, operator=, with a nonstatic member function that has only
one parameter. You cannot declare an overloaded assignment operator that is a nonmember function.
The following example shows how you can overload the assignment operator for a particular class:

struct X {
int data;
X& operator=(X& a) { return a; }
X& operator=(int a) {
data = a;
return *this;
}
};

int main() {
X x1, x2;
x1 = x2; // call x1.operator=(x2)
x1 = 5; // call x1.operator=(5)
}

The assignment x1 = x2 calls the copy assignment operator X& X::operator=(X&). The
assignment x1 = 5 calls the copy assignment operator X& X::operator=(int). The compiler
implicitly declares a copy assignment operator for a class if you do not define one yourself.
Consequently, the copy assignment operator (operator=) of a derived class hides the copy
assignment operator of its base class.

However, you can declare any copy assignment operator as virtual. The following example
demonstrates this:

#include <iostream>
using namespace std;

struct A {
A& operator=(char) {
cout << "A& A::operator=(char)" << endl;
return *this;
}
virtual A& operator=(const A&) {
cout << "A& A::operator=(const A&)" << endl;
return *this;
}
};

struct B : A {
B& operator=(char) {
cout << "B& B::operator=(char)" << endl;
return *this;
}
virtual B& operator=(const A&) {
cout << "B& B::operator=(const A&)" << endl;
return *this;
}
};

struct C : B { };

int main() {
B b1;
B b2;
A* ap1 = &b1;
A* ap2 = &b1;
*ap1 = 'z';
*ap2 = b2;

C c1;
// c1 = 'z';
}

The following is the output of the above example:

A& A::operator=(char)
B& B::operator=(const A&)

The assignment *ap1 = 'z' calls A& A::operator=(char). Because this operator has not been
declared virtual, the compiler chooses the function based on the type of the pointer ap1. The
assignment *ap2 = b2 calls B& B::operator=(const &A). Because this operator has been
declared virtual, the compiler chooses the function based on the type of the object that the pointer
ap1 points to. The compiler would not allow the assignment c1 = 'z' because the implicitly declared
copy assignment operator declared in class C hides B& B::operator=(char).

Overloading binary operators (C++ only)

You overload a binary unary operator with either a nonstatic member function that has one parameter,
or a nonmember function that has two parameters. Suppose a binary operator @ is called with the
statement t @ u, where t is an object of type T, and u is an object of type U. A nonstatic member
function that overloads this operator would have the following form:

return_type operator@(T)

A nonmember function that overloads the same operator would have the following form:

return_type operator@(T, U)

An overloaded binary operator may return any type.

The following example overloads the * operator:

struct X {

// member binary operator


void operator*(int) { }
};

// non-member binary operator


void operator*(X, float) { }

int main() {
X x;
int y = 10;
float z = 10;

x * y;
x * z;
}

The call x * y is interpreted as x.operator*(y). The call x * z is interpreted as operator*(x,


z).

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.


Overloading function calls (C++ only)

The function call operator, when overloaded, does not modify how functions are called. Rather, it
modifies how the operator is to be interpreted when applied to objects of a given type.

You overload the function call operator, operator(), with a nonstatic member function that has any
number of parameters. If you overload a function call operator for a class its declaration will have the
following form:

return_type operator()(parameter_list)

Unlike all other overloaded operators, you can provide default arguments and ellipses in the argument
list for the function call operator.

The following example demonstrates how the compiler interprets function call operators:

struct A {
void operator()(int a, char b, ...) { }
void operator()(char c, int d = 20) { }
};

int main() {
A a;
a(5, 'z', 'a', 0);
a('z');
// a();
}

The function call a(5, 'z', 'a', 0) is interpreted as a.operator()(5, 'z', 'a', 0). This
calls void A::operator()(int a, char b, ...). The function call a('z') is interpreted as
a.operator()('z'). This calls void A::operator()(char c, int d = 20). The compiler
would not allow the function call a() because its argument list does not match any function call
parameter list defined in class A.

The following example demonstrates an overloaded function call operator:

class Point {
private:
int x, y;
public:
Point() : x(0), y(0) { }
Point& operator()(int dx, int dy) {
x += dx;
y += dy;
return *this;
}
};

int main() {
Point pt;

// Offset this coordinate x with 3 points


// and coordinate y with 2 points.
pt(3, 2);
}
The above example reinterprets the function call operator for objects of class Point. If you treat an
object of Point like a function and pass it two integer arguments, the function call operator will add
the values of the arguments you passed to Point::x and Point::y respectively.

Bitwise negation operator ~

The ~ (bitwise negation) operator yields the bitwise complement of the operand. In the binary
representation of the result, every bit has the opposite value of the same bit in the binary
representation of the operand. The operand must have an integral type. The result has the same type
as the operand but is not an lvalue.

Suppose x represents the decimal value 5. The 16-bit binary representation of x is:

0000000000000101

The expression ~x yields the following result (represented here as a 16-bit binary number):

1111111111111010

Note that the ~ character can be represented by the trigraph ??-.

The 16-bit binary representation of ~0 is:

1111111111111111
IBM extension

The bitwise negation operator has been extended to handle complex types. With a complex type, the
operator computes the complex conjugate of the operand by reversing the sign of the imaginary part.

End of IBM extension

Destructors (C++ only)

Destructors are usually used to deallocate memory and do other cleanup for a class object and its
class members when the object is destroyed. A destructor is called for a class object when that object
passes out of scope or is explicitly deleted.

A destructor is a member function with the same name as its class prefixed by a ~ (tilde). For example:

class X {
public:
// Constructor for class X
X();
// Destructor for class X
~X();
};

A destructor takes no arguments and has no return type. Its address cannot be taken. Destructors
cannot be declared const, volatile, const volatile or static. A destructor can be declared
virtual or pure virtual.
If no user-defined destructor exists for a class and one is needed, the compiler implicitly declares a
destructor. This implicitly declared destructor is an inline public member of its class.

The compiler will implicitly define an implicitly declared destructor when the compiler uses the
destructor to destroy an object of the destructor's class type. Suppose a class A has an implicitly
declared destructor. The following is equivalent to the function the compiler would implicitly define for
A:

A::~A() { }

The compiler first implicitly defines the implicitly declared destructors of the base classes and nonstatic
data members of a class A before defining the implicitly declared destructor of A

A destructor of a class A is trivial if all the following are true:

• It is implicitly defined
• All the direct base classes of A have trivial destructors
• The classes of all the nonstatic data members of A have trivial destructors

If any of the above are false, then the destructor is nontrivial.

A union member cannot be of a class type that has a nontrivial destructor.

Class members that are class types can have their own destructors. Both base and derived classes
can have destructors, although destructors are not inherited. If a base class A or a member of A has a
destructor, and a class derived from A does not declare a destructor, a default destructor is generated.

The default destructor calls the destructors of the base class and members of the derived class.

The destructors of base classes and members are called in the reverse order of the completion of their
constructor:

1. The destructor for a class object is called before destructors for members and bases are
called.
2. Destructors for nonstatic members are called before destructors for base classes are called.
3. Destructors for nonvirtual base classes are called before destructors for virtual base classes
are called.

When an exception is thrown for a class object with a destructor, the destructor for the temporary
object thrown is not called until control passes out of the catch block.

Destructors are implicitly called when an automatic object (a local object that has been declared auto
or register, or not declared as static or extern) or temporary object passes out of scope. They
are implicitly called at program termination for constructed external and static objects. Destructors are
invoked when you use the delete operator for objects created with the new operator.

For example:

#include <string>

class Y {
private:
char * string;
int number;
public:
// Constructor
Y(const char*, int);
// Destructor
~Y() { delete[] string; }
};

// Define class Y constructor


Y::Y(const char* n, int a) {
string = strcpy(new char[strlen(n) + 1 ], n);
number = a;
}

int main () {
// Create and initialize
// object of class Y
Y yobj = Y("somestring", 10);

// ...

// Destructor ~Y is called before


// control returns from main()
}

You can use a destructor explicitly to destroy objects, although this practice is not recommended.
However to destroy an object created with the placement new operator, you can explicitly call the
object's destructor. The following example demonstrates this:

#include <new>
#include <iostream>
using namespace std;
class A {
public:
A() { cout << "A::A()" << endl; }
~A() { cout << "A::~A()" << endl; }
};
int main () {
char* p = new char[sizeof(A)];
A* ap = new (p) A;
ap->A::~A();
delete [] p;
}

The statement A* ap = new (p) A dynamically creates a new object of type A not in the free store
but in the memory allocated by p. The statement delete [] p will delete the storage allocated by p,
but the run time will still believe that the object pointed to by ap still exists until you explicitly call the
destructor of A (with the statement ap->A::~A()).

Temporary objects (C++ only)

Temporary objects are unnamed objects created on the stack by the compiler. They are used during
reference initialization and during evaluation of expressions including standard type conversions,
argument passing, function returns, and evaluation of the throw expression.

When a temporary object is created to initialize a reference variable, the name of the temporary object
has the same scope as that of the reference variable. When a temporary object is created during the
evaluation of a full-expression (an expression that is not a subexpression of another expression), it is
destroyed as the last step in its evaluation that lexically contains the point where it was created.

There are two exceptions in the destruction of full-expressions:

• The expression appears as an initializer for a declaration defining an object: the temporary
object is destroyed when the initialization is complete.
• A reference is bound to a temporary object: the temporary object is destroyed at the end of
the reference's lifetime.

If a temporary object is created for a class with constructors, the compiler calls the appropriate
(matching) constructor to create the temporary object.

When a temporary object is destroyed and a destructor exists, the compiler calls the destructor to
destroy the temporary object. When you exit from the scope in which the temporary object was
created, it is destroyed. If a reference is bound to a temporary object, the temporary object is
destroyed when the reference passes out of scope unless it is destroyed earlier by a break in the flow
of control. For example, a temporary object created by a constructor initializer for a reference member
is destroyed on leaving the constructor.

In cases where such temporary objects are redundant, the compiler does not construct them, in order
to create more efficient optimized code. This behavior could be a consideration when you are
debugging your programs, especially for memory problems.

Pseudo-destructors (C++ only)

A pseudo-destructor is a destructor of a nonclass type.

Pseudo-destructor syntax

>>-+-+----+--+-----------------------+--type_name--::--~--
type_name-----------------+-><
| '-::-' '-nested_name_specifier-'
|
+-+----+--nested_name_specifier--template--template_identifier--::--~--
type_name-+
| '-::-'
|
'-+----+--+-----------------------+--~--
type_name--------------------------------'
'-::-' '-nested_name_specifier-'

The following example calls the pseudo destructor for an integer type:

typedef int I;
int main() {
I x = 10;
x.I::~I();
x = 20;
}

The call to the pseudo destructor, x.I::~I(), has no effect at all. Object x has not been destroyed;
the assignment x = 20 is still valid. Because pseudo destructors require the syntax for explicitly
calling a destructor for a nonclass type to be valid, you can write code without having to know whether
or not a destructor exists for a given type.
Default constructors (C++ only)

A default constructor is a constructor that either has no parameters, or if it has parameters, all the
parameters have default values.

If no user-defined constructor exists for a class A and one is needed, the compiler implicitly declares a
default parameterless constructor A::A(). This constructor is an inline public member of its class. The
compiler will implicitly define A::A() when the compiler uses this constructor to create an object of
type A. The constructor will have no constructor initializer and a null body.

The compiler first implicitly defines the implicitly declared constructors of the base classes and
nonstatic data members of a class A before defining the implicitly declared constructor of A. No default
constructor is created for a class that has any constant or reference type members.

A constructor of a class A is trivial if all the following are true:

• It is implicitly defined
• A has no virtual functions and no virtual base classes
• All the direct base classes of A have trivial constructors
• The classes of all the nonstatic data members of A have trivial constructors

If any of the above are false, then the constructor is nontrivial.

A union member cannot be of a class type that has a nontrivial constructor.

Like all functions, a constructor can have default arguments. They are used to initialize member
objects. If default values are supplied, the trailing arguments can be omitted in the expression list of
the constructor. Note that if a constructor has any arguments that do not have default values, it is not a
default constructor.

A copy constructor for a class A is a constructor whose first parameter is of type A&, const A&,
volatile A&, or const volatile A&. Copy constructors are used to make a copy of one class
object from another class object of the same class type. You cannot use a copy constructor with an
argument of the same type as its class; you must use a reference. You can provide copy constructors
with additional parameters as long as they all have default arguments. If a user-defined copy
constructor does not exist for a class and one is needed, the compiler implicitly creates a copy
constructor, with public access, for that class. A copy constructor is not created for a class if any of its
members or base classes have an inaccessible copy constructor.

The following code fragment shows two classes with constructors, default constructors, and copy
constructors:

class X {
public:

// default constructor, no arguments


X();

// constructor
X(int, int , int = 0);

// copy constructor
X(const X&);

// error, incorrect argument type


X(X);
};

class Y {
public:

// default constructor with one


// default argument
Y( int = 0);

// default argument
// copy constructor
Y(const Y&, int = 0);
};

Copy constructors (C++ only)

The copy constructor lets you create a new object from an existing one by initialization. A copy
constructor of a class A is a non-template constructor in which the first parameter is of type A&, const
A&, volatile A&, or const volatile A&, and the rest of its parameters (if there are any) have
default values.

If you do not declare a copy constructor for a class A, the compiler will implicitly declare one for you,
which will be an inline public member.

The following example demonstrates implicitly defined and user-defined copy constructors:

#include <iostream>
using namespace std;

struct A {
int i;
A() : i(10) { }
};

struct B {
int j;
B() : j(20) {
cout << "Constructor B(), j = " << j << endl;
}

B(B& arg) : j(arg.j) {


cout << "Copy constructor B(B&), j = " << j << endl;
}

B(const B&, int val = 30) : j(val) {


cout << "Copy constructor B(const B&, int), j = " << j << endl;
}
};

struct C {
C() { }
C(C&) { }
};
int main() {
A a;
A a1(a);
B b;
const B b_const;
B b1(b);
B b2(b_const);
const C c_const;
// C c1(c_const);
}

The following is the output of the above example:

Constructor B(), j = 20
Constructor B(), j = 20
Copy constructor B(B&), j = 20
Copy constructor B(const B&, int), j = 30

The statement A a1(a) creates a new object from a with an implicitly defined copy constructor. The
statement B b1(b) creates a new object from b with the user-defined copy constructor B::B(B&).
The statement B b2(b_const) creates a new object with the copy constructor B::B(const B&,
int). The compiler would not allow the statement C c1(c_const) because a copy constructor that
takes as its first parameter an object of type const C& has not been defined.

The implicitly declared copy constructor of a class A will have the form A::A(const A&) if the
following are true:

• The direct and virtual bases of A have copy constructors whose first parameters have been
qualified with const or const volatile
• The nonstatic class type or array of class type data members of A have copy constructors
whose first parameters have been qualified with const or const volatile

If the above are not true for a class A, the compiler will implicitly declare a copy constructor with the
form A::A(A&).

The compiler cannot allow a program in which the compiler must implicitly define a copy constructor for
a class A and one or more of the following are true:

• Class A has a nonstatic data member of a type which has an inaccessible or ambiguous copy
constructor.
• Class A is derived from a class which has an inaccessible or ambiguous copy constructor.

The compiler will implicitly define an implicitly declared constructor of a class A if you initialize an
object of type A or an object derived from class A.

An implicitly defined copy constructor will copy the bases and members of an object in the same order
that a constructor would initialize the bases and members of the object.

Overview of constructors and destructors (C++ only)


Because classes have complicated internal structures, including data and functions, object initialization
and cleanup for classes is much more complicated than it is for simple data structures. Constructors
and destructors are special member functions of classes that are used to construct and destroy class
objects. Construction may involve memory allocation and initialization for objects. Destruction may
involve cleanup and deallocation of memory for objects.

Like other member functions, constructors and destructors are declared within a class declaration.
They can be defined inline or external to the class declaration. Constructors can have default
arguments. Unlike other member functions, constructors can have member initialization lists. The
following restrictions apply to constructors and destructors:

• Constructors and destructors do not have return types nor can they return values.
• References and pointers cannot be used on constructors and destructors because their
addresses cannot be taken.
• Constructors cannot be declared with the keyword virtual.
• Constructors and destructors cannot be declared static, const, or volatile.
• Unions cannot contain class objects that have constructors or destructors.

Constructors and destructors obey the same access rules as member functions. For example, if you
declare a constructor with protected access, only derived classes and friends can use it to create class
objects.

The compiler automatically calls constructors when defining class objects and calls destructors when
class objects go out of scope. A constructor does not allocate memory for the class object its this
pointer refers to, but may allocate storage for more objects than its class object refers to. If memory
allocation is required for objects, constructors can explicitly call the new operator. During cleanup, a
destructor may release objects allocated by the corresponding constructor. To release objects, use the
delete operator.

Derived classes do not inherit or overload constructors or destructors from their base classes, but they
do call the constructor and destructor of base classes. Destructors can be declared with the keyword
virtual.

Constructors are also called when local or temporary class objects are created, and destructors are
called when local or temporary objects go out of scope.

You can call member functions from constructors or destructors. You can call a virtual function, either
directly or indirectly, from a constructor or destructor of a class A. In this case, the function called is the
one defined in A or a base class of A, but not a function overridden in any class derived from A. This
avoids the possibility of accessing an unconstructed object from a constructor or destructor. The
following example demonstrates this:

#include <iostream>
using namespace std;

struct A {
virtual void f() { cout << "void A::f()" << endl; }
virtual void g() { cout << "void A::g()" << endl; }
virtual void h() { cout << "void A::h()" << endl; }
};

struct B : A {
virtual void f() { cout << "void B::f()" << endl; }
B() {
f();
g();
h();
}
};

struct C : B {
virtual void f() { cout << "void C::f()" << endl; }
virtual void g() { cout << "void C::g()" << endl; }
virtual void h() { cout << "void C::h()" << endl; }
};

int main() {
C obj;
}

The following is the output of the above example:

void B::f()
void A::g()
void A::h()

The constructor of B does not call any of the functions overridden in C because C has been derived
from B, although the example creates an object of type C named obj.

You can use the typeid or the dynamic_cast operator in constructors or destructors, as well as
member initializers of constructors.

The terminate() function (C++ only)

In some cases, the exception handling mechanism fails and a call to void terminate() is made.
This terminate() call occurs in any of the following situations:

• The exception handling mechanism cannot find a handler for a thrown exception. The
following are more specific cases of this:
o During stack unwinding, a destructor throws an exception and that exception is not
handled.
o The expression that is thrown also throws an exception, and that exception is not
handled.
o The constructor or destructor of a nonlocal static object throws an exception, and the
exception is not handled.
o A function registered with atexit() throws an exception, and the exception is not
handled. The following demonstrates this:
o extern "C" printf(char* ...);
o #include <exception>
o #include <cstdlib>
o using namespace std;
o
o void f() {
o printf("Function f()\n");
o throw "Exception thrown from f()";
o }
o
o void g() { printf("Function g()\n"); }
o void h() { printf("Function h()\n"); }
o
o void my_terminate() {
o printf("Call to my_terminate\n");
o abort();
o }
o
o int main() {
o set_terminate(my_terminate);
o atexit(f);
o atexit(g);
o atexit(h);
o printf("In main\n");
}
The following is the output of the above example:
In main
Function h()
Function g()
Function f()
Call to my_terminate
To register a function with atexit(), you pass a parameter to atexit() a pointer
to the function you want to register. At normal program termination, atexit() calls
the functions you have registered with no arguments in reverse order. The atexit()
function is in the <cstdlib> library.
• A throw expression without an operand tries to rethrow an exception, and no exception is
presently being handled.
• A function f() throws an exception that violates its exception specification. The
unexpected() function then throws an exception which violates the exception specification
of f(), and the exception specification of f() did not include the class
std::bad_exception.
• The default value of unexpected_handler is called.

The terminate() function calls the function pointed to by terminate_handler. By default,


terminate_handler points to the function abort(), which exits from the program. You can replace
the default value of terminate_handler with the function set_terminate().

A terminate function cannot return to its caller, either by using return or by throwing an exception.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy