You are on page 1of 23

To implement virtual functions, C++ uses a special form of late binding known as the

virtual table. The virtual table is a lookup table of functions used to resolve function
calls in a dynamic/late binding manner. The virtual table sometimes goes by other
names, such as “vtable”, “virtual function table”, “virtual method table”, or “dispatch
table”.

Because knowing how the virtual table works is not necessary to use virtual functions,
this section can be considered optional reading.

The virtual table is actually quite simple, though it’s a little complex to describe in
words. First, every class that uses virtual functions (or is derived from a class that
uses virtual functions) is given it’s own virtual table. This table is simply a static array
that the compiler sets up at compile time. A virtual table contains one entry for each
virtual function that can be called by objects of the class. Each entry in this table is
simply a function pointer that points to the most-derived function accessible by that
class.

Second, the compiler also adds a hidden pointer to the base class, which we will call
*__vptr. *__vptr is set (automatically) when a class instance is created so that it
points to the virtual table for that class. Unlike the *this pointer, which is actually a
function parameter used by the compiler to resolve self-references, *__vptr is a real
pointer. Consequently, it makes each class object allocated bigger by the size of one
pointer. It also means that *__vptr is inherited by derived classes, which is important.

By now, you’re probably confused as to how these things all fit together, so let’s take
a look at a simple example:

class Base
{
public:
virtual void function1() {};
virtual void function2() {};
};

class D1: public Base


{
public:
virtual void function1() {};
};

class D2: public Base


{
public:
virtual void function2() {};
};

Because there are 3 classes here, the compiler will set up 3 virtual tables: one for
Base, one for D1, and one for D2.

The compiler also adds a hidden pointer to the most base class that uses virtual
functions. Although the compiler does this automatically, we’ll put it in the next
example just to show where it’s added:
class Base
{
public:
FunctionPointer *__vptr;
virtual void function1() {};
virtual void function2() {};
};

class D1: public Base


{
public:
virtual void function1() {};
};

class D2: public Base


{
public:
virtual void function2() {};
};

When a class object is created, *__vptr is set to point to the virtual table for that class.
For example, when a object of type Base is created, *__vptr is set to point to the
virtual table for Base. When objects of type D1 or D2 are constructed, *__vptr is set
to point to the virtual table for D1 or D2 respectively.

Now, let’s talk about how these virtual tables are filled out. Because there are only
two virtual functions here, each virtual table will have two entries (one for
function1(), and one for function2()). Remember that when these virtual tables are
filled out, each entry is filled out with the most-derived function an object of that class
type can call.

Base’s virtual table is simple. An object of type Base can only access the members of
Base. Base has no access to D1 or D2 functions. Consequently, the entry for function1
points to Base::function1(), and the entry for function2 points to Base::function2().

D1’s virtual table is slightly more complex. An object of type D1 can access members
of both D1 and Base. However, D1 has overridden function1(), making
D1::function1() more derived than Base::function1(). Consequently, the entry for
function1 points to D1::function1(). D1 hasn’t overridden function2(), so the entry for
function2 will point to Base::function2().

D2’s virtual table is similar to D1, except the entry for function1 points to
Base::function1(), and the entry for function2 points to D2::function2().

Here’s a picture of this graphically:


Although this diagram is kind of crazy looking, it’s really quite simple: the *__vptr in
each class points to the virtual table for that class. The entries in the virtual table point
to the most-derived version of the function objects of that class are allowed to call.

So consider what happens when we create an object of type D1:

int main()
{
D1 cClass;
}

Because cClass is a D1 object, cClass has it’s *__vptr set to the D1 virtual table.

Now, let’s set a base pointer to D1:

int main()
{
D1 cClass;
Base *pClass = &cClass;
}

Note that because pClass is a base pointer, it only points to the Base portion of cClass.
However, also note that *__vptr is in the Base portion of the class, so pClass has
access to this pointer. Finally, note that pClass->__vptr points to the D1 virtual table!
Consequently, even though pClass is of type Base, it still has access to D1’s virtual
table.

So what happens when we try to call pClass->function1()?

int main()
{
D1 cClass;
Base *pClass = &cClass;
pClass->function1();
}

First, the program recognizes that function1() is a virtual function. Second, uses
pClass->__vptr(as vptr now points to D1 virtual table when D1’s object got created)
to get to D1’s virtual table. Third, it looks up which version of function1() to call in
D1’s virtual table. This has been set to D1::function1(). Therefore, pClass-
>function1() resolves to D1::function1()!

Now, you might be saying, “But what if Base really pointed to a Base object instead
of a D1 object. Would it still call D1::function1()?”. The answer is no.

int main()
{
Base cClass;
Base *pClass = &cClass;
pClass->function1();
}

In this case, when cClass is created, __vptr points to Base’s virtual table, not D1’s
virtual table. Consequently, pClass->__vptr will also be pointing to Base’s virtual
table. Base’s virtual table entry for function1() points to Base::function1(). Thus,
pClass->function1() resolves to Base::function1(), which is the most-derived version
of function1() that a Base object should be able to call.

By using these tables, the compiler and program are able to ensure function calls
resolve to the appropriate virtual function, even if you’re only using a pointer or
reference to a base class!

Calling a virtual function is slower than calling a non-virtual function for a couple of
reasons: First, we have to use the *__vptr to get to the appropriate virtual table.
Second, we have to index the virtual table to find the correct function to call. Only
then can we call the function. As a result, we have to do 3 operations to find the
function to call, as opposed to 2 operations for a normal indirect function call, or one
operation for a direct function call. However, with modern computers, this added time
is usually fairly insignificant.

Virtual inheritance
In the C++ programming language, virtual inheritance is a kind of inheritance that
can be used under multiple inheritance. When a class C has a direct or indirect base
class X, it may inherit it indirectly through several inheritance lines. All the virtual
occurrences of X will result in a single internal instance of X within an instance of C.
This can be used to solve some problems (particularly the "diamond problem"), by
clarifying ambiguity over which ancestor class to use. It is used when inheritance is
representing restrictions of a set rather than composition of parts. A multiply-inherited
base class is denoted as virtual with the virtual keyword

The problem
Consider the following class hierarchy.

class Animal
{
public:
virtual void eat();
};

class Mammal : public Animal


{
public:
virtual void walk();
};

class WingedAnimal : public Animal


{
public:
virtual void flap();
};

// A bat is a winged mammal


class Bat : public Mammal, public WingedAnimal {};

Bat bat;

As declared above, a call to bat.eat() is ambiguous. The ambiguity is caused by the


way C++ implementations typically represent classes. In particular, inheritance is
simply a matter of putting parent and child classes one after the other in memory.
Thus, Bat is represented as (Animal,Mammal,Animal,WingedAnimal,Bat), which
makes Animal duplicated (in other words, Bat owns two different Animal instances,
namely a Mammal::Animal and a WingedAnimal::Animal). To disambiguate, one
would have to explicitly call either bat.Mammal::eat() or
bat.WingedAnimal::eat().

Similarly, an attempt to directly cast a Bat object to an Animal would fail, since the
cast is ambiguous.

Animal a = (Animal)Bat(); //error: which Animal instance should a Bat


cast into,
//a Mammal::Animal or a
WingedAnimal::Animal?
As noted, the code would fail to compile, despite the fact that the two different
Animals are 'identical' (for example, no virtual members of Animal are being
overridden by Mammal or WingedAnimal). To fix the code without using virtual
inheritance, it would be necessary to first cast to one of the two inherited classes and
then make the cast to Animal.

Animal a = (Animal)(Mammal)Bat(); //ok: compiler chooses


Mammal::Animal after
//cast to Mammal

This situation is sometimes referred to as diamond inheritance because the


inheritance diagram is in the shape of a diamond. Virtual inheritance can help to solve
this problem.

The solution
We can re-declare our classes as follows:

class Animal
{
public:
virtual void eat();
};

// Two classes virtually inheriting Animal:


class Mammal : public virtual Animal
{
public:
virtual void walk();
};

class WingedAnimal : public virtual Animal


{
public:
virtual void flap();
};

// A bat is still a winged mammal


class Bat : public Mammal, public WingedAnimal {};

The Animal portion of Bat::WingedAnimal is now the same Animal instance as the
one used by Bat::Mammal, which is to say that a Bat has only one, shared, Animal
instance in its representation and so a call to Bat::eat() is unambiguous.
Additionally, a direct cast from Bat to Animal is also unambiguous, now that there
exists only one Animal instance which Bat could be converted to.

This is implemented by providing Mammal and WingedAnimal with a vtable pointer


(or "vpointer") since, e.g., the memory offset between the beginning of a Mammal and
of its Animal part is unknown until runtime. Thus Bat becomes
(vpointer,Mammal,vpointer,WingedAnimal,Bat,Animal). There are two vtable
pointers, one per inheritance hierarchy that virtually inherits Animal. In this example,
one for Mammal and one for WingedAnimal. The object size has therefore increased by
two pointers, but now there is only one Animal and no ambiguity. All objects of type
Bat will have the same vpointers, but each Bat object will contain its own unique
Animal object. If another class inherits from Mammal, such as Squirrel, then the
vpointer in the Mammal object in a Squirrel will be different from the vpointer in the
Mammal object in a Bat, although they can still be essentially the same in the special
case that the Squirrel part of the object has the same size as the Bat part, because
then the distance from the Mammal to the Animal part is the same. The vtables are not
really the same, but all essential information in them (the distance) is.

In C++ there are three inheritance access specifiers:

• public

• protected

• private

Any of these three inheritance access specifiers can be modified with the virtual

keyword.

The three access modifiers public, protected and private are analogous to the

access modifiers used for class members.

public

When a base class is specified as public ie: class c : public base {}; the base

class can be seen by anyone who has access to the derived class. That is, any members

inherited from base can be seen by code accessing c.

protected

When a base class is specified as protected ie: class c : protected base {};

the base class can only be seen by subclasses of C.

private

When a base class is specified as private ie: class c : private base {}; the

base class can only be seen by the class C itself.

Examples of how this plays out:

struct X {
public:
void A() {}
};

struct Y {
public:
void B() {}
};

struct Z {
public:
void C() {}
};

struct Q : public X, protected Y, private Z {


public:
void Test()
{
A(); // OK
B(); // OK
C(); // OK
}
};

struct R : public Q {
public:
void Test2()
{
A(); // OK
B(); // OK
C(); // NOT OK

Q t;
Y *y = &t // OK
Z *z = &t // NOT OK
}
};

int main(int argc, char **argv) {


Q t1;
t1.A(); // OK
t1.B(); // NOT OK
t1.C(); // NOT OK

R t2;
t2.A(); // OK
t2.B(); // NOT OK
t2.C(); // NOT OK

X *x = &t1; // OK
Y *y = &t1; // NOT OK
Z *z = &t1; // NOT OK

x = &t2; // OK
y = &t2; // NOT OK
z = &t2; // NOT OK

The example given is pretty vague... Use the one below if you like it.

Class A

public:

int apub;
private:

int aprv;

protected:

int apro;

Basic thumb rule in inheritance. You cannot inherit private members.

Public visibility mode during Inheritance

---------------------------------------------------

Public inheritance will inherit protected members,methods of base class with visibilty

modifier as protected.

Public inheritance will inherit public members,methods of base class with visibilty modifier

as public.

Class B : public A

public:

int bpub; // also has access to apub

private:

int bprv;

protected:

int bpro; // also has access to apro

Private visibility mode during Inheritance

---------------------------------------------------

Private inheritance will inherit protected as well as public members,methods of base class

with visibilty modifier as private.

Class B : private A

public:

int bpub;

private:

int bprv; // also has access to apub,apro

protected:

int bpro;

}
Protected visibility mode during Inheritance

---------------------------------------------------------

Private inheritance will inherit protected as well as public members,methods of base class

with visibilty modifier as protected.

Class B : private A

public:

int bpub;

private:

int bprv;

protected:

int bpro; // also has access to apub,apro

Friendship and inheritance


Published by Juan Soulie
Last update on Sep 29, 2009 at 10:55am UTC

Friend functions
In principle, private and protected members of a class cannot be accessed from outside
the same class in which they are declared. However, this rule does not affect friends.

Friends are functions or classes declared as such.

If we want to declare an external function as friend of a class, thus allowing this function
to have access to the private and protected members of this class, we do it by declaring a
prototype of this external function within the class, and preceding it with the keyword
friend:

1 // friend functions 24
2 #include <iostream>
3 using namespace std;
4
5 class CRectangle {
6 int width, height;
7 public:
8 void set_values (int, int);
9 int area () {return (width *
10 height);}
11 friend CRectangle duplicate
12 (CRectangle);
13 };
14
15 void CRectangle::set_values (int
16 a, int b) {
17 width = a;
18 height = b;
19 }
20
21 CRectangle duplicate (CRectangle
22 rectparam)
23 {
24 CRectangle rectres;
25 rectres.width =
26 rectparam.width*2;
27 rectres.height =
28 rectparam.height*2;
29 return (rectres);
30 }
31
32 int main () {
CRectangle rect, rectb;
rect.set_values (2,3);
rectb = duplicate (rect);
cout << rectb.area();
return 0;
}

The duplicate function is a friend of CRectangle. From within that function we have
been able to access the members width and height of different objects of type
CRectangle, which are private members. Notice that neither in the declaration of
duplicate() nor in its later use in main() have we considered duplicate a member of
class CRectangle. It isn't! It simply has access to its private and protected members
without being a member.

The friend functions can serve, for example, to conduct operations between two different
classes. Generally, the use of friend functions is out of an object-oriented programming
methodology, so whenever possible it is better to use members of the same class to
perform operations with them. Such as in the previous example, it would have been
shorter to integrate duplicate() within the class CRectangle.

Friend classes
Just as we have the possibility to define a friend function, we can also define a class as
friend of another one, granting that first class access to the protected and private
members of the second one.

1 // friend class 16
2 #include <iostream>
3 using namespace std;
4
5 class CSquare;
6
7 class CRectangle {
8 int width, height;
9 public:
10 int area ()
11 {return (width * height);}
12 void convert (CSquare a);
13 };
14
15 class CSquare {
16 private:
17 int side;
18 public:
19 void set_side (int a)
20 {side=a;}
21 friend class CRectangle;
22 };
23
24 void CRectangle::convert (CSquare
25 a) {
26 width = a.side;
27 height = a.side;
28 }
29
30 int main () {
31 CSquare sqr;
32 CRectangle rect;
33 sqr.set_side(4);
34 rect.convert(sqr);
35 cout << rect.area();
36 return 0;
}

In this example, we have declared CRectangle as a friend of CSquare so that


CRectangle member functions could have access to the protected and private members
of CSquare, more concretely to CSquare::side, which describes the side width of the
square.

You may also see something new at the beginning of the program: an empty declaration of
class CSquare. This is necessary because within the declaration of CRectangle we refer
to CSquare (as a parameter in convert()). The definition of CSquare is included later,
so if we did not include a previous empty declaration for CSquare this class would not be
visible from within the definition of CRectangle.

Consider that friendships are not corresponded if we do not explicitly specify so. In our
example, CRectangle is considered as a friend class by CSquare, but CRectangle does
not consider CSquare to be a friend, so CRectangle can access the protected and private
members of CSquare but not the reverse way. Of course, we could have declared also
CSquare as friend of CRectangle if we wanted to.

Another property of friendships is that they are not transitive: The friend of a friend is not
considered to be a friend unless explicitly specified.

Inheritance between classes


A key feature of C++ classes is inheritance. Inheritance allows to create classes which are
derived from other classes, so that they automatically include some of its "parent's"
members, plus its own. For example, we are going to suppose that we want to declare a
series of classes that describe polygons like our CRectangle, or like CTriangle. They
have certain common properties, such as both can be described by means of only two
sides: height and base.

This could be represented in the world of classes with a class CPolygon from which we
would derive the two other ones: CRectangle and CTriangle.
The class CPolygon would contain members that are common for both types of polygon.
In our case: width and height. And CRectangle and CTriangle would be its derived
classes, with specific features that are different from one type of polygon to the other.

Classes that are derived from others inherit all the accessible members of the base class.
That means that if a base class includes a member A and we derive it to another class with
another member called B, the derived class will contain both members A and B.

In order to derive a class from another, we use a colon (:) in the declaration of the
derived class using the following format:

class derived_class_name: public base_class_name


{ /*...*/ };

Where derived_class_name is the name of the derived class and base_class_name is


the name of the class on which it is based. The public access specifier may be replaced
by any one of the other access specifiers protected and private. This access specifier
limits the most accessible level for the members inherited from the base class: The
members with a more accessible level are inherited with this level instead, while the
members with an equal or more restrictive access level keep their restrictive level in the
derived class.

Exception Handling

Furthermore, exception handling in C++ propagates the exceptions up the stack; therefore,
if there are several functions called, but only one function that needs to reliably deal with errors,
the method C++ uses to handle exceptions means that it can easily handle those exceptions
without any code in the intermediate functions. One consequence is that functions don't need
to return error codes, freeing their return values for program logic.

When errors occur, the function generating the error can 'throw' an exception. For example,
take a sample function that does division:
const int DivideByZero = 10;
//....
double divide(double x, double y)
{
if(y==0)
{
throw DivideByZero;
}
return x/y;
}
The function will throw DivideByZero as an exception that can then be caught by an exception-
handling catch statement that catches exceptions of type int. The necessary construction for
catching exceptions is a try catch system. If you wish to have your program check for
exceptions, you must enclose the code that may have exceptions thrown in a try block. For
example:
try
{
divide(10, 0);
}
catch(int i)
{
if(i==DivideByZero)
{
cerr<<"Divide by zero error";
}
}
The catch statement catches exceptions that are of the proper type. You can, for example,
throw objects of a class to differentiate between several different exceptions. As well, once a
catch statement is executed, the program continues to run from the end of the catch.

It is often more useful for you to create a class that stores information on exceptions as they
occur. For example, it would be more useful if you had a class to handle exceptions.
class DivideByZero
{
public:
double divisor;
DivideByZero(double x);
};
DivideByZero::DivideByZero(double x) : divisor(x)
{}
int divide(int x, int y)
{
if(y==0)
{
throw DivideByZero(x);
}
}
try
{
divide(12, 0);
}
catch (DivideByZero divZero)
{
cerr<<"Attempted to divide "<<divZero.divisor<<" by zero";
}

If you wish to catch more than one possible exception, you can specify separate catch blocks for
each type of exception. It's also possible to have a general exception handler that will respond
to any thrown exception. To use it, simply use catch(...) for the catch statement and print a
general warning of some kind.

The handy thing to remember about exception handling is that the errors can be handled
outside of the regular code. This means that it is easier to structure the program code, and it
makes dealing with errors more centralized. Finally, because the exception is passed back up
the stack of calling functions, you can handle errors at any place you choose.

In C, you might see some error handling code to free memory and close files repeated five or or
six times, once for each possible error. A solution some programmers prefered was to use a
goto statement that jumped all the way to the cleanup code. Now, you can just surround your
code with a try-catch block and handle any cleanup following the catch (possibly with an
additional copy of your cleanup routine inside the catch block if you intend to throw the
exception again to alert the calling function of an error).

The try, catch, and throw Statements


Updated: February 2009
The following syntax shows a try block and its handlers:

try {
// code that could throw an exception
}
[ catch (exception-declaration) {
// code that executes when exception-declaration is thrown
// in the try block
}
[catch (exception-declaration) {
// code that handles another exception type
} ] . . . ]
// The following syntax shows a throw expression:
throw [expression]
Remarks

The C++ language provides built-in support for handling anomalous situations, known as exceptions,
which may occur during the execution of your program. The try, throw, and catch statements
implement exception handling. With C++ exception handling, your program can communicate
unexpected events to a higher execution context that is better able to recover from such abnormal
events. These exceptions are handled by code that is outside the normal flow of control. The Microsoft
C++ compiler implements the C++ exception handling model based on the ANSI C++ standard.

C++ also provides a way to explicitly specify whether a function can throw exceptions. You can use
exception specifications in function declarations to indicate that a function can throw an exception. For
example, an exception specification throw(...) tells the compiler that a function can throw an
exception, but doesn't specify the type, as in this example:

Copy Code
void MyFunc() throw(...) {
throw 1;
}

For more information, see Exception Specifications.

Note:

The Win32 structured exception-handling mechanism works with both C and C++ source files.
However, it is not specifically designed for C++. You can ensure that your code is more portable by
using C++ exception handling. Also, C++ exception handling is more flexible, in that it can handle
exceptions of any type. For C++ programs, it is recommended that you use the C++ exception-
handling mechanism (try, catch, throw) described in this topic.

The code after the try clause is the guarded section of code. The throw expression throws (raises) an
exception. The code block after the catch clause is the exception handler, and catches (handles) the
exception thrown by the throw expression. The exception-declaration statement indicates the type of
exception the clause handles. The type can be any valid data type, including a C++ class. If the
exception-declaration statement is an ellipsis (...), the catch clause handles any type of exception,
including C exceptions and system- or application-generated exceptions such as memory protection,
divide by zero, and floating-point violations. Such a handler must be the last handler for its try block.

The operand of throw is syntactically similar to the operand of a return statement.

Execution proceeds as follows:

1. Control reaches the try statement by normal sequential execution. The guarded section

within the try block is executed.


2. If no exception is thrown during execution of the guarded section, the catch clauses that

follow the try block are not executed. Execution continues at the statement after the last
catch clause following the associated try block.

3. If an exception is thrown during execution of the guarded section or in any routine the

guarded section calls (either directly or indirectly), an exception object is created from the
object created by the throw operand. (This implies that a copy constructor may be
involved.) At this point, the compiler looks for a catch clause in a higher execution context
that can handle an exception of the type thrown (or a catch handler that can handle any
type of exception). The catch handlers are examined in order of their appearance following
the try block. If no appropriate handler is found, the next dynamically enclosing try block is
examined. This process continues until the outermost enclosing try block is examined.

4. If a matching handler is still not found, or if an exception occurs while unwinding, but before

the handler gets control, the predefined run-time function terminate is called. If an
exception occurs after throwing the exception, but before the unwind begins, terminate is
called.

5. If a matching catch handler is found, and it catches by value, its formal parameter is

initialized by copying the exception object. If it catches by reference, the parameter is


initialized to refer to the exception object. After the formal parameter is initialized, the
process of unwinding the stack begins. This involves the destruction of all automatic objects
that were constructed (but not yet destructed) between the beginning of the try block
associated with the catch handler and the exception's throw site. Destruction occurs in
reverse order of construction. The catch handler is executed and the program resumes
execution following the last handler (that is, the first statement or construct which is not a
catch handler). Control can only enter a catch handler through a thrown exception, never
via a goto statement or a case label in a switch statement.

The following is a simple example of a try block and its associated catch handler. This example
detects failure of a memory allocation operation using the new operator. If new is successful, the
catch handler is never executed:

Copy Code
// exceptions_trycatchandthrowstatements.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main() {
char *buf;
try {
buf = new char[512];
if( buf == 0 )
throw "Memory allocation failure!";
}
catch( char * str ) {
cout << "Exception raised: " << str << '\n';
}
}

The operand of the throw expression specifies that an exception of type char * is being thrown. It is
handled by a catch handler that expresses the ability to catch an exception of type char *. In the
event of a memory allocation failure, this is the output from the preceding example:
Copy Code
Exception raised: Memory allocation failure!

The real power of C++ exception handling lies not only in its ability to deal with exceptions of varying
types, but also in its ability to automatically call destructor functions during stack unwinding, for all
local objects constructed before the exception was thrown.

The following example demonstrates C++ exception handling using classes with destructor semantics:

Example

Copy Code
// exceptions_trycatchandthrowstatements2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
void MyFunc( void );

class CTest {
public:
CTest() {};
~CTest() {};
const char *ShowReason() const {
return "Exception in CTest class.";
}
};

class CDtorDemo {
public:
CDtorDemo();
~CDtorDemo();
};

CDtorDemo::CDtorDemo() {
cout << "Constructing CDtorDemo.\n";
}

CDtorDemo::~CDtorDemo() {
cout << "Destructing CDtorDemo.\n";
}

void MyFunc() {
CDtorDemo D;
cout<< "In MyFunc(). Throwing CTest exception.\n";
throw CTest();
}

int main() {
cout << "In main.\n";
try {
cout << "In try block, calling MyFunc().\n";
MyFunc();
}
catch( CTest E ) {
cout << "In catch handler.\n";
cout << "Caught CTest exception type: ";
cout << E.ShowReason() << "\n";
}
catch( char *str ) {
cout << "Caught some other exception: " << str << "\n";
}
cout << "Back in main. Execution resumes here.\n";
}

Copy Code
In main.
In try block, calling MyFunc().
Constructing CDtorDemo.
In MyFunc(). Throwing CTest exception.
Destructing CDtorDemo.
In catch handler.
Caught CTest exception type: Exception in CTest class.
Back in main. Execution resumes here.
Comments

Note that in this example, the exception parameter (the argument to the catch clause) is declared in
both catch handlers:

Copy Code
catch( CTest E )
// ...
catch( char *str )
// ...

You do not need to declare this parameter; in many cases it may be sufficient to notify the handler
that a particular type of exception has occurred. However, if you do not declare an exception object in
the exception-declaration, you will not have access to that object in the catch handler clause.

A throw-expression with no operand re-throws the exception currently being handled. Such an
expression should appear only in a catch handler or in a function called from within a catch handler.
The re-thrown exception object is the original exception object (not a copy). For example:

Copy Code
try {
throw CSomeOtherException();
}
catch(...) { // Handle all exceptions
// Respond (perhaps only partially) to exception
throw; // Pass exception to some other handler
}

Exception Specifications
Exception specifications are used to provide summary information about what exceptions can be
thrown out of a function. For example:

Copy Code
void MyFunction(int i) throw(...);

An exception specification with an empty throw, as in

Copy Code
void MyFunction(int i) throw();

tells the compiler that the function does not throw any exceptions. It is the equivalent to using
__declspec(nothrow). For example:
Copy Code
// exceptions_trycatchandthrowstatements3.cpp
// compile with: /EHsc
#include <stdio.h>

void empty() throw() {


puts("In empty()");
}

void with_type() throw(int) {


puts("Will throw an int");
throw(1);
}

int main() {
try {
empty();
with_type();
}
catch (int) {
puts("Caught an int");
}
}

Visual C++ departs from the ANSI Standard in its implementation of exception specifications. The
following table summarizes the Visual C++ implementation of exception specifications:

Exception
specification Meaning

throw() The function does not throw an exception. However, if an exception is thrown out
of a function marked throw(), the Visual C++ compiler will not call unexpected
(see unexpected (CRT) and unexpected (<exception>) for more information). If a
function is marked with throw(), the Visual C++ compiler will assume that the
function does not throw C++ exceptions and generated code accordingly. Due to
code optimizations that maybe performed by the C++ compiler (based on the
assumption that the function does not throw any C++ exceptions) if function does
throw an exception, the program may not execute correctly.

throw(...) The function can throw an exception.

throw(type) The function can throw an exception of type type. However, in Visual C++ .NET,
this is interpreted as throw(...). See Function Exception Specifiers.

If exception handling is used in an application, there must be one or more functions that handle
thrown exceptions. Any functions called between the one that throws an exception and the one that
handles the exception must be capable of throwing the exception.

The throw behavior of a function depends on the following factors:

• Whether you are compiling the function under C or C++.

• Which /EH compiler option you use.

• Whether you explicitly specify the exception specification.

Explicit exception specifications are not allowed on C functions.

The following table summarizes the throw behavior of a function:


Function /EHsc /EHs /EHa /EHac

C function throw() throw(...) throw(...) throw(...)

C++ function with no exception specification throw(...) throw(...) throw(...) throw(...)

C++ function with throw() exception throw() throw() throw(...) throw(...)


specification

C++ function with throw(...) exception throw(...) throw(...) throw(...) throw(...)


specification

C++ function with throw(type) exception throw(...) throw(...) throw(...) throw(...)


specification
Example

Copy Code
// exception_specification.cpp
// compile with: /EHs
#include <stdio.h>

void handler() {
printf_s("in handler\n");
}

void f1(void) throw(int) {


printf_s("About to throw 1\n");
if (1)
throw 1;
}

void f5(void) throw() {


try {
f1();
}
catch(...) {
handler();
}
}

// invalid, doesn't handle the int exception thrown from f1()


// void f3(void) throw() {
// f1();
// }

void __declspec(nothrow) f2(void) {


try {
f1();
}
catch(int) {
handler();
}
}

// only valid if compiled without /EHc


// /EHc means assume extern "C" functions don't throw exceptions
extern "C" void f4(void);
void f4(void) {
f1();
}

int main() {
f2();
try {
f4();
}
catch(...) {
printf_s("Caught exception from f4\n");
}
f5();
}

Copy Code
About to throw 1
in handler
About to throw 1
Caught exception from f4
About to throw 1
in handler

Function-try Blocks
A function-try block catches exceptions generated from a call made in a constructor's initialization list.

Example

The following example uses a function-try block:

Visual C++

Copy Code
// NVC_Function_Try.cpp
// Compile by using /EHsc
#include <iostream>
#include <ostream>
#include <stdexcept>
#include <string>
using namespace std;

class Name
{
public:
Name(const string& strFirstName, const string& strLastName)
{
if(strFirstName == "")
{
throw runtime_error("Error in Name::Name(): first name
parameter must not be blank.");
}

if(strLastName == "")
{
throw runtime_error("Error in Name::Name(): last name
parameter must not be blank.");
}

m_firstName = strFirstName;
m_lastName = strLastName;

cout << "Inside Name::Name(): My name is " << GetName() <<


"." << endl;
}
~Name()
{
cout << "Inside Name::~Name(): Destroying " << GetName() <<
"." << endl;
}

string GetName()
{
return m_firstName + " " + m_lastName;
}

private:
string m_firstName;
string m_lastName;
};

class Person
{
public:
Person(const string& strFirstName, const string& strLastName)
// begin function-try block
try : m_name(strFirstName, strLastName){}
catch (const runtime_error& err)
{
cout << "Caught exception inside Person::Person()." << endl;
cout << err.what() << endl;
// The exception will be automatically rethrown.
}

~Person()
{
cout << "Inside Person::~Person(): Destroying " <<
m_name.GetName() << "." << endl;
}

private:
Name m_name;
};

int main()
{
try
{
// Test 1 - Valid Parameters
{
cout << "Attempting to construct an object of class
Person." << endl;
cout << "Passing parameters: \"John\", \"Smith\"" <<
endl;
Person person1("John", "Smith");
}

cout << "Test 1 completed." << endl;

// Test 2 - Invalid first name parameter


{
// Note that an exception will be thrown in Name's
constructor,
// as the first name parameter must not be blank.
// Because this exception is thrown, person2's
destructor
// is never called.
cout << "Attempting to construct an object of class
Person." << endl;
cout << "Passing parameters: \"\", \"Jones\"" << endl;
Person person2("", "Jones");
}
}
catch (const runtime_error&)
{
cout << "Exception caught within main()." << endl;
}
}

// Output:
// --------------------------
// Attempting to construct an object of class Person.
// Passing parameters: "John", "Smith"
// Inside Name::Name(): My name is John Smith.
// Inside Person::~Person(): Destroying John Smith.
// Inside Name::~Name(): Destroying John Smith.
// Test 1 completed.
// Attempting to construct an object of class Person.
// Passing parameters: "", "Jones"
// Caught exception inside Person::Person().
// Error in Name::Name(): first name
// Exception caught within main().

Exception Handling: Default Synchronous Exception


Model
In previous versions of Visual C++, the C++ exception handling mechanism supported asynchronous
(hardware) exceptions by default. Under the asynchronous model, the compiler assumes any
instruction may generate an exception.

With the new synchronous exception model, now the default, exceptions can be thrown only with a
throw statement. Therefore, the compiler can assume that exceptions happen only at a throw
statement or at a function call. This model allows the compiler to eliminate the mechanics of tracking
the lifetime of certain unwindable objects, and to significantly reduce the code size, if the objects'
lifetimes do not overlap a function call or a throw statement. The two exception handling models,
synchronous and asynchronous, are fully compatible and can be mixed in the same application.

See /EH for information on enabling exception handling.

You might also like