Thursday 12 March 2009

Free C++ Compilers

I know there are a lot of C++ compilers availiable and the best free compiler I've used is code:blocks. I know there is a quite a few compilers that could be better than code:blocks. But I would be unaware of it since I'm happy with code:blocks. Although Code:BLocks has a friendly user interface it is a little bit more complicated to get everything running. A good compiler for a programmer who has good C++ knowledge.
You can get code:blocks from this website
www.codeblocks.org/
Dev C++ is also a very good compiler and I have had very good results with this compiler and is why I recomend it for begginers to C++. It has a very easy and friendly user interface and is easy for anyone.
You can get Dev C++ from there website which is located at
www.bloodshed.net/devcpp.html

Saturday 7 March 2009

Stupid C++ Tricks

I recently came across this C++ Soup post, which demonstrates some cute C++ tricks. Now by cute, I mean stupid, similar to Dave Letterman’s segment “stupid pet tricks” (you can google that if you’ve never seen this). It’s a useless language exercise with little practical application except to show how obfuscated one can make C++. Are there any benefit to these tricks? Lets explore.

Now all C++ programmers do this (myself included) just to see if they understand template programming, so keep in mind that this is NOT a critique of this particular author, who I’m sure is a C++ Ninja. It’s just a recent example that triggered this rant. No, just have a look at half the boost libraries to see this thinking taken to the extreme. Or even the C++ standard library; does anyone really use the cumbersome std::for_each function or any of that bind stuff? They all feel like they’re unfinished ideas: they’re onto something, but they’re not quite there yet.

These (what I’m calling) C++ tricks are often segments of templated C++ code that push generic programming to solve some kind of basic problem, that is typically solved using simpler (but more verbose) code. A trick author is often amazed (and proud) at how small or flexible the code is, but hopefully realizes that the amount of work or expertise required to make the trick outweighs most benefits. The code is then shelved. Lets cut this silliness out.

Furthermore, most application developers will steer clear (or be ignorant) of such tricks, and popular C++ libraries do well to not require such expertise from their users.

Is there any benefit to these tricks? Yes, only to show what could be possible with C++.

C++ is an extremely powerful language, giving you compile time dynamic/generic programming with no loss of runtime performance. No other language does this so fully and completely, and C++ is still the only language option in many demanding areas.

However, the language needs to grow, and it needs to grow fast. We must look at what these tricks are trying to do, and then think how we can change the language to do the same thing in a sane, logical fashion. C++0x is working on this with lambdas, type inference, better error reporting and some other niceties. But we needed these features yesterday, and get people using them. Lets steal more features from other languages. Lets turn up the meta programming capabilities so we can extend the language without meta-compilers and preprocessors, which until now provide the bulk of the useful new language extensions.

There is no reason why C++ can’t offer easy to use and powerful compile-time dynamic programming, resulting in code that looks like a dynamic scripting language, but with safer types and kick-ass performance, memory use and code size.

Monday 2 March 2009

How to load the PNG image?

hmm, to load the PNG image, most people use libpng. But, wait.. But WAIT!! That library is “NOT SAFE FOR DIRECT USE”. The API is Awful, yeah.. It's Right. If you don’t believe me, spend a day with it, struggle through it, THEN check out OpenIL. This is an example of how DIFFICULT using libpng directly is.

#include 
#include

#undef _UNICODE
#include "il.h"

#pragma comment( lib, "DevIL.lib" )

// Wow. DevIL is amazing.

// From http://gpwiki.org/index.php/DevIL:Tutorials:Basics

// The library consists of three sub-libraries:
// * IL - main DevIL library. It allows you to load and save images to files. Every function in this library have 'il' prefixed to their name.
// * ILU - this library contains functions for altering images. Every function in this library have 'ilu' prefixed to their name.
// * ILUT - this library connects DevIL with OpenGL. Every function in this library have 'ilut' prefixed to their name.

int main()
{
ilInit();
printf("DevIL has been initialized\n");

// Loading an image
ILboolean result = ilLoadImage( "4px.png" ) ;

if( result == true )
{
printf("the image loaded successfully\n");
}
else
{
printf("The image failed to load\n" ) ;

ILenum err = ilGetError() ;
printf( "the error %d\n", err );
printf( "string is %s\n", ilGetString( err ) );
}

int size = ilGetInteger( IL_IMAGE_SIZE_OF_DATA ) ;
printf("Data size: %d\n", size );
ILubyte * bytes = ilGetData() ;

for( int i = 0 ; i < size; i++ )
{
// see we should see the byte data of the image now.
printf( "%d\n", bytes[ i ] );
}
}

Wednesday 25 February 2009

Quick Tips On Using Whole Program Optimization

If you’re writing native C++ code, you can typically speed up your optimized code by about another 3-4% by adding the /GL flag to your compiles. This flag tells the compiler to defer code generation until you link your program. Then at link time the linker calls back to the compiler to finish compilation. If you compile all your sources this way, the compiler optimizes your program as a whole rather than one source file at a time. For users building with the IDE, this option is found under the C/C++ optimization settings, and is already on by default for retail builds in new projects.

Using Whole Program Optimization provides the optimizer with a number of extra optimization opportunities, but I’ll give just one example. Many people are already familiar with the benefits of inlining a called function into the caller. We can only do inlining when we are generating code for both the calling function and the called function at the same time. With Link Time Code Gen we can inline functions from one source file into callers defined in another source file, as long as both source files were compiled with /GL.

If you do use /GL, here are four caveats to keep in mind:

1. When building from the command line or via makefiles, you need to add the /LTCG switch to the link command line to tell the linker to expect to see one or more object files that were compiled with /GL. If you don’t, some build time will be wasted because the linker will have to start over when it gets to the module compiled with /GL. If you build through the IDE this is in your project configuration settings on the Linker optimization page.

2. Using /GL reduces your compile times, but your link time will increase, because work is being moved to during the link. Overall build time might increase a little, but shouldn’t increase a lot.

3. Don’t compile managed code with /GL. Link time code gen provides little or no benefit to managed code, and this option combination (/GL /clr) is being removed in the next compiler release, so you can future-proof your build by using link time code generation only for native code. If you’re building managed code using the IDE, the default setting is to use /GL in release builds, and I recommend you disable it for managed code. For mixed managed and native code, compiling only the native code with /GL and linking with /LTCG gives best results.

4. Never use /GL for code you intend to put in a library and ship to your customers. Doing so means that your customers will be doing the code gen for your library when they link their application. Since some of your customers could have different versions of the compiler, shipping a lib built this way could cause various maintenance problems for you. If your customer’s compiler is from a prior release, their link may fail. If their version is newer than yours, the code they generate won’t be exactly equal to what you’ve tested, and could behave differently for them than when you tested it. In VS 2008, the IDE default for the class library template release configuration is to build using /GL, and I strongly encourage everyone to reset that.

Here are links for more information on this topic:

The /GL compiler switch (http://msdn.microsoft.com/en-us/library/0zza0de8.aspx)

The /LTCG linker switch (http://msdn.microsoft.com/en-us/library/xbf3tbeh.aspx)

A detailed article about Link Time Code Generation (http://msdn.microsoft.com/en-us/magazine/cc301698.aspx)

Saturday 14 February 2009

Just simple guess game

Free-submit.co.cc - FREE SUBMIT YOUR BLOG AND GET HIGH TRAFFIC


In this posting, I will show you about a simple guess game.
This is the code.

#include
int main()
{
int myBirthday = 13;
int guess;

cout << "Please guess the day of my birth, from 1 to 31"<<< "Enter your guess please"; cin >> guess;

if (guess < else="" if="" guess="">31)
{
cout << "Pretty long month, genius!!" <<< "Incredible,, you are right. Congratulations.."<< else="" cout=""><< "Lower" <<>

Wednesday 11 February 2009

Essentials of System Analysis and Design or Expert C Programming

Expert C Programming

Author: Peter van der Linden

This is a very different book on the C language! In an easy, conversational style, Peter van der Linden, of Sun's compiler and OS kernel group, presents dozens of astonishing examples drawn from practical experience, including:

• Software that blew up the space probe to Venus
• The C bug that shut down the entire AT&T phone system
• C programmer job interview secrets
• Why programmers can't tell Halloween from Christmas day
• The C code for a complete BASIC interpreter

Expert C Programming reveals the coding techniques used by the best C programmers. It relates C to other languages, and includes an introduction to C++ that can be understood by an programmer without weeks of mind-bending study. Covering both the IBM PC and UNIX systems, it is an entertaining and educational romp through C showing how experts really use it. Expert C Programming is a must read for anyone who wants to learn more about the implementation, practical use, and folklore of C.

"Not just clearly written, but fun to read. The tone and style of this text should make this a popular book with professional programmers. However, the tone of this book will make it very popular with undergraduates. Appendix A alone would make the purchase of this book a must. It's filled with great advice."

—Professor Jack Beidler, Chairman, Department of Computer Science, University of Scranton

"So that's why extern char *cp isn't the same as extern char cp. I knew that it didn't work despite their superficial equivalence, but I didn't know why. I also love the job interview test questions on C."

—David S.Platt, Rolling Thunder Computing

"In Expert C Programming, Peter van der Linden combines C language expertise and a subtle sense of humor to deliver a C programming book that stands out from the pack. In a genre too often known for windy, lifeless prose, van der Linden's crisp language, tongue-in-cheek attitude, and real-world examples engage and instruct."

—John Barry, author of Sunburst, Technobabble, and other books



Table of Contents:

Preface

Acknowledgments

Introduction
1C Through the Mists of Time1
2It's Not a Bug, It's a Language Feature31
3Unscrambling Declarations in C63
4The Shocking Truth: C Arrays and Pointers Are NOT the Same!95
5Thinking of Linking109
6Poetry in Motion: Runtime Data Structures137
7Thanks for the Memory165
8Why Programmers Can't Tell Halloween from Christmas Day201
9More about Arrays239
10More About Pointers263
11You Know C, So C++ is Easy!293

Appendix: Secrets of Programmer Job Interviews333

Index349

Tuesday 10 February 2009

Nested Classes

Classes can be defined inside other classes. Classes that are defined inside other classes are called nested classes. Nested classes are used in situations where the nested class has a close conceptual relationship to its surrounding class. For example, with the class string a type string::iterator is available which will provide all characters that are stored in the string. This string::iterator type could be defined as an object iterator, defined as nested class in the class string.

A class can be nested in every part of the surrounding class: in the public, protected or private section. Such a nested class can be considered a member of the surrounding class. The normal access and rules in classes apply to nested classes. If a class is nested in the public section of a class, it is visible outside the surrounding class. If it is nested in the protected section it is visible in subclasses, derived from the surrounding class , if it is nested in the private section, it is only visible for the members of the surrounding class.

The surrounding class has no special privileges with respect to the nested class. So, the nested class still has full control over the accessibility of its members by the surrounding class. For example, consider the following class definition:

    class Surround
{
public:
class FirstWithin
{
int d_variable;

public:
FirstWithin();
int var() const;
};
private:
class SecondWithin
{
int d_variable;

public:
SecondWithin();
int var() const;
};
};
inline int Surround::FirstWithin::var() const
{
return d_variable;
}
inline int Surround::SecondWithin::var() const
{
return d_variable;
}
In this definition access to the members is defined as follows:
  • The class FirstWithin is visible both outside and inside Surround. The class FirstWithin therefore has global scope.
  • The constructor FirstWithin() and the member function var() of the class FirstWithin are also globally visible.
  • The int d_variable datamember is only visible to the members of the class FirstWithin. Neither the members of Surround nor the members of SecondWithin can access d_variable of the class FirstWithin directly.
  • The class SecondWithin is only visible inside Surround. The public members of the class SecondWithin can also be used by the members of the class FirstWithin, as nested classes can be considered members of their surrounding class.
  • The constructor SecondWithin() and the member function var() of the class SecondWithin can also only be reached by the members of Surround (and by the members of its nested classes).
  • The int d_variable datamember of the class SecondWithin is only visible to the members of the class SecondWithin. Neither the members of Surround nor the members of FirstWithin can access d_variable of the class SecondWithin directly.
  • As always, an object of the class type is required before its members can be called. This also holds true for nested classes.
If the surrounding class should have access rights to the private members of its nested classes or if nested classes should have access rights to the private members of the surrounding class, the classes can be defined as friend classes.

The nested classes can be considered members of the surrounding class, but the members of nested classes are not members of the surrounding class. So, a member of the class Surround may not access FirstWithin::var() directly. This is understandable considering the fact that a Surround object is not also a FirstWithin or SecondWithin object. In fact, nested classes are just typenames. It is not implied that objects of such classes automatically exist in the surrounding class. If a member of the surrounding class should use a (non-static) member of a nested class then the surrounding class must define a nested class object, which can thereupon be used by the members of the surrounding class to use members of the nested class.

For example, in the following class definition there is a surrounding class Outer and a nested class Inner. The class Outer contains a member function caller() which uses the inner object that is composed in Outer to call the infunction() member function of Inner:

    class Outer
{
public:
void caller();

private:
class Inner
{
public:
void infunction();
};
Inner d_inner; // class Inner must be known
};
void Outer::caller()
{
d_inner.infunction();
}
The mentioned function Inner::infunction() can be called as part of the inline definition of Outer::caller(), even though the definition of the class Inner is yet to be seen by the compiler. On the other hand, the compiler must have seen the definition of the class Inner before a data member of that class can be defined.

Saturday 7 February 2009

Intel releases updated concurrent C/C++ tools

Intel Corp. has announced version 0.3.0 of its Concurrent Collections for C/C++, downloadable from the company's site.

Among the new and updated features Release 0.3.0 includes are: steps that can now be specified with different priorities to improve performance; support for garbage collection by ref-counting to reduce memory usage.

The collections provide the tools for constructing C++ programs that execute in parallel while allowing application developers to ignore issues of parallelism such as low-level threading constructs or the scheduling and distribution of computations.

The model lets programmers specify high-level computational steps including inputs and outputs without imposing unnecessary ordering on their execution. Code within the computational steps is written using standard serial constructs of the C++ language.

Data is either local to a computational step or it is explicitly produced and consumed by them. An application in this programming model supports multiple styles of parallelism (e.g., data, task, pipeline parallel).

While the interface between the computational steps and the runtime system remains unchanged, a wide range of runtime systems may target different architectures (e.g., shared memory, distributed) or support different scheduling methodologies (e.g., static or dynamic).

Intel is also providing a runtime system for shared memory systems that supports parallel execution although it is not yet highly optimised.

The birth of C++

In the coming two years after C was released, the code written in C began to suffer from a problem. As the programmers harnessed the power of Personal Computer, the software grew more complex, and the C programs have gotten longer and longer. This meant that these programs were also harder to maintain. Some functions needed to communicate with other functions, but there was no standard way of thinking about data organization. In long programs, the code was practically infested with functions in the global scope. One of the few ways to separate data was by using separate C header (.h) and C source (.c) files. Other than that, the language's features that would help organize the code to ensure readability of large programs were simply missing.

There had to be a solution. In 1983, Bjarne Stroustrup developed such a solution, and named it the C++ programming language. He drew inspiration from some of the previous languages that allowed object-oriented programming. One of those languages was Simula67. It can be said that one of the greatest addition to C's supset, the C++ language, was that C++ introduced programmers to the concept of an object. An object is an abstraction of a problem. Not only does the use of the concept of objects in a programming language reduce the size of the program, it also makes the program much more readable and compact. The notion of objects gave the origin to the concept of Object-Oriented programming which I discuss in my Introduction to Object-Oriented Programming.

Why was it named C++?

Initially the C++ language was named "C with Classes" because you could still write C-like programs in C++ but you could also use what we call classes. I will be sure to talk about classes and other object-oriented C++ concepts in the following tutorials. You might ask, why a successor to C is called C++ and what is this double plus sign business all about? If you were writing a program in C and you wanted to add two numbers together such as 1 + 1, in the listing (or source code) of your program, you would write it just that way as: 1 + 1. Notice that in computer programming, the plus sign is called an operator, it directs the compiler to add two values together. Plenty of times programmers need to add the digit 1 to another digit stored in what is called a variable. Because of the frequent use of these simple arithmetics in general computer programs, a new operator called postfix increment (represented by a double plus sequence: ++) may be used to simply add 1 to the existing value, thus avoiding the redundancy of typing: 1 + 1. It just makes the program code look cleaner and easier to read. Therefore, you can see that the expression C++ actually has a meaning. It is C incremented by 1, or in other words, a version of C programming language that contains additional features. You may also think of C++ as an augmented version of C.

On the other hand, the reason the C programming language is called C, is that it is a successor to the language called B. Simple isn't it? Strange as it is, there was never a programming language called A. Or as far as we know, if there was a language called A, it never saw the light of success or popularity. If you are interested in learning about how C++ falls into the history of computer programming languages, you may want to look at the chart of evolution of computer languages. This hierarchy shows where each computer language came from. As you can see the Assembly Language (which is a low-level programming language) on this chart is located in the upper left corner because it is one of the first languages ever designed and can be considered the grand-father of all computer programming languages. Additionally you may be able to gain an insight from the list of programming languages by date that lists languages in chronological order.

Saturday 31 January 2009

Standard C Date & Time

asctimea textual version of the time
clockreturns the amount of time that the program has been running
ctimereturns a specifically formatted version of the time
difftimethe difference between two times
gmtimereturns a pointer to the current Greenwich Mean Time
localtimereturns a pointer to the current time
mktimereturns the calendar version of a given time
setlocalesets the current locale
strftimereturns individual elements of the date and time
timereturns the current calendar time of the system

Standard C Math

absabsolute value
acosarc cosine
asinarc sine
atanarc tangent
atan2arc tangent, using signs to determine quadrants
ceilthe smallest integer not less than a certain value
coscosine
coshhyperbolic cosine
divreturns the quotient and remainder of a division
expreturns “e” raised to a given power
fabsabsolute value for floating-point numbers
floorreturns the largest integer not greater than a given value
fmodreturns the remainder of a division
frexpdecomposes a number into scientific notation
labsabsolute value for long integers
ldexpcomputes a number in scientific notation
ldivreturns the quotient and remainder of a division, in long integer form
lognatural logarithm (to base e)
log10common logarithm (to base 10)
modfdecomposes a number into integer and fractional parts
powreturns a given number raised to another number
sinsine
sinhhyperbolic sine
sqrtsquare root
tantangent
tanhhyperbolic tangent

Monday 26 January 2009

Keywords in C++

C++'s keywords are a superset of C's keywords. Here is a list of all keywords of the language:

 and        const     float         operator static_cast    using
and_eq const_cast for or struct virtual
asm continue friend or_eq switch void
auto default goto private template volatile
bitand delete if protected this wchar_t
bitor do inline public throw while
bool double int register true xor
break dynamic_cast long reinterpret_cast try xor_eq
case else mutable return typedef
catch enum namespace short typeid
char explicit new signed typename
class extern not sizeof union
compl false not_eq static unsigned

Note the
operator keywords: and, and_eq, bitand, bitor, compl,
not, not_eq, or, or_eq, xor
and xor_eq are symbolic alternatives for,
respectively, &&, &=, &, |, ~, !, !=, ||, |=, ^ and ^=.

Friday 23 January 2009

Type Casting

onverting an expression of a given type into another type is known as type-casting. We have already seen some ways to type cast:

Implicit conversion

Implicit conversions do not require any operator. They are automatically performed when a value is copied to a compatible type. For example:
short a=2000;
int b;
b=a;

Here, the value of a has been promoted from short to int and we have not had to specify any type-casting operator. This is known as a standard conversion. Standard conversions affect fundamental data types, and allow conversions such as the conversions between numerical types (short to int, int to float, double to int...), to or from bool, and some pointer conversions. Some of these conversions may imply a loss of precision, which the compiler can signal with a warning. This can be avoided with an explicit conversion.

Implicit conversions also include constructor or operator conversions, which affect classes that include specific constructors or operator functions to perform conversions. For example:

class A {};
class B { public: B (A a) {} };

A a;
B b=a;

Here, a implicit conversion happened between objects of class A and class B, because B has a constructor that takes an object of class A as parameter. Therefore implicit conversions from A to B are allowed.

Explicit conversion

C++ is a strong-typed language. Many conversions, specially those that imply a different interpretation of the value, require an explicit conversion. We have already seen two notations for explicit type conversion: functional and c-like casting:
short a=2000;
int b;
b = (int) a; // c-like cast notation
b = int (a); // functional notation

The functionality of these explicit conversion operators is enough for most needs with fundamental data types. However, these operators can be applied indiscriminately on classes and pointers to classes, which can lead to code that while being syntactically correct can cause runtime errors. For example, the following code is syntactically correct:

// class type-casting
#include
using namespace std;

class CDummy {
float i,j;
};

class CAddition {
int x,y;
public:
CAddition (int a, int b) { x=a; y=b; }
int result() { return x+y;}
};

int main () {
CDummy d;
CAddition * padd;
padd = (CAddition*) &d;
cout <<>result();
return 0;
}
 

The program declares a pointer to CAddition, but then it assigns to it a reference to an object of another incompatible type using explicit type-casting:

padd = (CAddition*) &d;

Traditional explicit type-casting allows to convert any pointer into any other pointer type, independently of the types they point to. The subsequent call to member result will produce either a run-time error or a unexpected result.

In order to control these types of conversions between classes, we have four specific casting operators: dynamic_cast, reinterpret_cast, static_cast and const_cast. Their format is to follow the new type enclosed between angle-brackets (<>) and immediately after, the expression to be converted between parentheses.

dynamic_cast (expression)
reinterpret_cast (expression)
static_cast (expression)
const_cast (expression)

The traditional type-casting equivalents to these expressions would be:

(new_type) expression
new_type (expression)

but each one with its own special characteristics:

dynamic_cast

dynamic_cast can be used only with pointers and references to objects. Its purpose is to ensure that the result of the type conversion is a valid complete object of the requested class.

Therefore, dynamic_cast is always successful when we cast a class to one of its base classes:

class CBase { };
class CDerived: public CBase { };

CBase b; CBase* pb;
CDerived d; CDerived* pd;

pb = dynamic_cast(&d); // ok: derived-to-base
pd = dynamic_cast(&b); // wrong: base-to-derived

The second conversion in this piece of code would produce a compilation error since base-to-derived conversions are not allowed with dynamic_cast unless the base class is polymorphic.

When a class is polymorphic, dynamic_cast performs a special checking during runtime to ensure that the expression yields a valid complete object of the requested class:

// dynamic_cast
#include
#include
using namespace std;

class CBase { virtual void dummy() {} };
class CDerived: public CBase { int a; };

int main () {
try {
CBase * pba = new CDerived;
CBase * pbb = new CBase;
CDerived * pd;

pd = dynamic_cast(pba);
if (pd==0) cout << "Null pointer on first type-cast" << endl;

pd = dynamic_cast(pbb);
if (pd==0) cout << "Null pointer on second type-cast" << endl;

} catch (exception& e) {cout << "Exception: " << e.what();}
return 0;
}
Null pointer on second type-cast
Compatibility note: dynamic_cast requires the Run-Time Type Information (RTTI) to keep track of dynamic types. Some compilers support this feature as an option which is disabled by default. This must be enabled for runtime type checking using dynamic_cast to work properly.

The code tries to perform two dynamic casts from pointer objects of type CBase* (pba and pbb) to a pointer object of type CDerived*, but only the first one is successful. Notice their respective initializations:

CBase * pba = new CDerived;
CBase * pbb = new CBase;

Even though both are pointers of type CBase*, pba points to an object of type CDerived, while pbb points to an object of type CBase. Thus, when their respective type-castings are performed using dynamic_cast, pba is pointing to a full object of class CDerived, whereas pbb is pointing to an object of class CBase, which is an incomplete object of class CDerived.

When dynamic_cast cannot cast a pointer because it is not a complete object of the required class -as in the second conversion in the previous example- it returns a null pointer to indicate the failure. If dynamic_cast is used to convert to a reference type and the conversion is not possible, an exception of type bad_cast is thrown instead.

dynamic_cast can also cast null pointers even between pointers to unrelated classes, and can also cast pointers of any type to void pointers (void*).

static_cast

static_cast can perform conversions between pointers to related classes, not only from the derived class to its base, but also from a base class to its derived. This ensures that at least the classes are compatible if the proper object is converted, but no safety check is performed during runtime to check if the object being converted is in fact a full object of the destination type. Therefore, it is up to the programmer to ensure that the conversion is safe. On the other side, the overhead of the type-safety checks of dynamic_cast is avoided.
class CBase {};
class CDerived: public CBase {};
CBase * a = new CBase;
CDerived * b = static_cast(a);

This would be valid, although b would point to an incomplete object of the class and could lead to runtime errors if dereferenced.

static_cast can also be used to perform any other non-pointer conversion that could also be performed implicitly, like for example standard conversion between fundamental types:

double d=3.14159265;
int i = static_cast<int>(d);

Or any conversion between classes with explicit constructors or operator functions as described in "implicit conversions" above.

reinterpret_cast

reinterpret_cast converts any pointer type to any other pointer type, even of unrelated classes. The operation result is a simple binary copy of the value from one pointer to the other. All pointer conversions are allowed: neither the content pointed nor the pointer type itself is checked.

It can also cast pointers to or from integer types. The format in which this integer value represents a pointer is platform-specific. The only guarantee is that a pointer cast to an integer type large enough to fully contain it, is granted to be able to be cast back to a valid pointer.

The conversions that can be performed by reinterpret_cast but not by static_cast have no specific uses in C++ are low-level operations, whose interpretation results in code which is generally system-specific, and thus non-portable. For example:

class A {};
class B {};
A * a = new A;
B * b = reinterpret_cast(a);

This is valid C++ code, although it does not make much sense, since now we have a pointer that points to an object of an incompatible class, and thus dereferencing it is unsafe.

const_cast

This type of casting manipulates the constness of an object, either to be set or to be removed. For example, in order to pass a const argument to a function that expects a non-constant parameter:
// const_cast
#include
using namespace std;

void print (char * str)
{
cout << str << endl;
}

int main () {
const char * c = "sample text";
print ( const_cast<char *> (c) );
return 0;
}
sample text

typeid

typeid allows to check the type of an expression:

typeid (expression)

This operator returns a reference to a constant object of type type_info that is defined in the standard header file . This returned value can be compared with another one using operators == and != or can serve to obtain a null-terminated character sequence representing the data type or class name by using its name() member.

// typeid
#include
#include
using namespace std;

int main () {
int * a,b;
a=0; b=0;
if (typeid(a) != typeid(b))
{
cout << "a and b are of different types:\n";
cout << "a is: " << typeid(a).name() << '\n';
cout << "b is: " << typeid(b).name() << '\n';
}
return 0;
}
a and b are of different types:
a is: int *
b is: int

When typeid is applied to classes typeid uses the RTTI to keep track of the type of dynamic objects. When typeid is applied to an expression whose type is a polymorphic class, the result is the type of the most derived complete object:

// typeid, polymorphic class
#include
#include
#include
using namespace std;

class CBase { virtual void f(){} };
class CDerived : public CBase {};

int main () {
try {
CBase* a = new CBase;
CBase* b = new CDerived;
cout << "a is: " << typeid(a).name() << '\n';
cout << "b is: " << typeid(b).name() << '\n';
cout << "*a is: " << typeid(*a).name() << '\n';
cout << "*b is: " << typeid(*b).name() << '\n';
} catch (exception& e) { cout << "Exception: " << e.what() << endl; }
return 0;
}
a is: class CBase *
b is: class CBase *
*a is: class CBase
*b is: class CDerived

Notice how the type that typeid considers for pointers is the pointer type itself (both a and b are of type class CBase *). However, when typeid is applied to objects (like *a and *b) typeid yields their dynamic type (i.e. the type of their most derived complete object).

If the type typeid evaluates is a pointer preceded by the dereference operator (*), and this pointer has a null value, typeid throws a bad_typeid exception.

Exceptions

Exceptions provide a way to react to exceptional circumstances (like runtime errors) in our program by transferring control to special functions called handlers.

To catch exceptions we must place a portion of code under exception inspection. This is done by enclosing that portion of code in a try block. When an exceptional circumstance arises within that block, an exception is thrown that transfers the control to the exception handler. If no exception is thrown, the code continues normally and all handlers are ignored.

A exception is thrown by using the throw keyword from inside the try block. Exception handlers are declared with the keyword catch, which must be placed immediately after the try block:

// exceptions
#include
using namespace std;

int main () {
try
{
throw 20;
}
catch (int e)
{
cout << "An exception occurred. Exception Nr. " << e << endl;
}
return 0;
}
An exception occurred. Exception Nr. 20

The code under exception handling is enclosed in a try block. In this example this code simply throws an exception:

throw 20;

A throw expression accepts one parameter (in this case the integer value 20), which is passed as an argument to the exception handler.

The exception handler is declared with the catch keyword. As you can see, it follows immediately the closing brace of the try block. The catch format is similar to a regular function that always has at least one parameter. The type of this parameter is very important, since the type of the argument passed by the throw expression is checked against it, and only in the case they match, the exception is caught.

We can chain multiple handlers (catch expressions), each one with a different parameter type. Only the handler that matches its type with the argument specified in the throw statement is executed.

If we use an ellipsis (...) as the parameter of catch, that handler will catch any exception no matter what the type of the throw exception is. This can be used as a default handler that catches all exceptions not caught by other handlers if it is specified at last:

try {
// code here
}
catch (int param) { cout << "int exception"; }
catch (char param) { cout << "char exception"; }
catch (...) { cout << "default exception"; }

In this case the last handler would catch any exception thrown with any parameter that is neither an int nor a char.

After an exception has been handled the program execution resumes after the try-catch block, not after the throw statement!.

It is also possible to nest try-catch blocks within more external try blocks. In these cases, we have the possibility that an internal catch block forwards the exception to its external level. This is done with the expression throw; with no arguments. For example:

try {
try {
// code here
}
catch (int n) {
throw;
}
}
catch (...) {
cout << "Exception occurred";
}

Exception specifications

When declaring a function we can limit the exception type it might directly or indirectly throw by appending a throw suffix to the function declaration:

float myfunction (char param) throw (int);

This declares a function called myfunction which takes one agument of type char and returns an element of type float. The only exception that this function might throw is an exception of type int. If it throws an exception with a different type, either directly or indirectly, it cannot be caught by a regular int-type handler.

If this throw specifier is left empty with no type, this means the function is not allowed to throw exceptions. Functions with no throw specifier (regular functions) are allowed to throw exceptions with any type:

int myfunction (int param) throw(); // no exceptions allowed
int myfunction (int param); // all exceptions allowed

Standard exceptions

The C++ Standard library provides a base class specifically designed to declare objects to be thrown as exceptions. It is called exception and is defined in the header file under the namespace std. This class has the usual default and copy constructors, operators and destructors, plus an additional virtual member function called what that returns a null-terminated character sequence (char *) and that can be overwritten in derived classes to contain some sort of description of the exception.
// standard exceptions
#include
#include
using namespace std;

class myexception: public exception
{
virtual const char* what() const throw()
{
return "My exception happened";
}
} myex;

int main () {
try
{
throw myex;
}
catch (exception& e)
{
cout << e.what() << endl;
}
return 0;
}
My exception happened.

We have placed a handler that catches exception objects by reference (notice the ampersand & after the type), therefore this catches also classes derived from exception, like our myex object of class myexception.

All exceptions thrown by components of the C++ Standard library throw exceptions derived from this std::exception class. These are:

exceptiondescription
bad_allocthrown by new on allocation failure
bad_castthrown by dynamic_cast when fails with a referenced type
bad_exceptionthrown when an exception type doesn't match any catch
bad_typeidthrown by typeid
ios_base::failurethrown by functions in the iostream library

For example, if we use the operator new and the memory cannot be allocated, an exception of type bad_alloc is thrown:

try
{
int * myarray= new int[1000];
}
catch (bad_alloc&)
{
cout << "Error allocating memory." << endl;
}

It is recommended to include all dynamic memory allocations within a try block that catches this type of exception to perform a clean action instead of an abnormal program termination, which is what happens when this type of exception is thrown and not caught. If you want to force a bad_alloc exception to see it in action, you can try to allocate a huge array; On my system, trying to allocate 1 billion ints threw a bad_alloc exception.

Because bad_alloc is derived from the standard base class exception, we can handle that same exception by catching references to the exception class:

// bad_alloc standard exception
#include
#include
using namespace std;

int main () {
try
{
int* myarray= new int[1000];
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
return 0;
}
 

Thursday 22 January 2009

C and C++ are CRAZY!

I’ve learned a lot of crazy things about C and C++ in the last few years, as far as parsing goes. The one that’s always blown me away the most is that parsing C++ is undecidable: you can’t properly parse C++ without doing template instantiation, but template instantiation is turing-complete.

But every time I think I’ve gotten to the point where C and C++ can’t faze me anymore, I find something new. Like this, from the Wikipedia article about operator precedence in C and C++:

The binding of operators in C and C++ is specified (in the corresponding Standards) by a factored language grammar, rather than a precedence table. This creates some subtle conflicts. For example, in C, the syntax for a conditional expression is:

logical-OR-expression ? expression :
conditional-expression

while in C++ it is:

logical-or-expression ? expression :
assignment-expression

Hence, the expression:

e = a ? b : c = d

is parsed differently in the two languages. In C, this expression is parsed as:

e = ((a ? b : c) = d)

which is a semantic error, since the result of a conditional-expression is not an lvalue. In C++, it is parsed as:

e = (a ? b : (c = d))

which is a valid expression.

WHAT?? I had to try this out and determine whether it was true or some crazy Wikipedia anonymous editor who was trying to drive me mad. So I wrote the simple test program:

int main() {
int e = 1, a = 2, b = 3, c = 4, d = 5;
e = a ? b : c = d;
return e;
}

…and attempted to compile it first with gcc as a .c, then with g++ as a .cc, and sure enough:

$ gcc -o /tmp/test /tmp/test.c
/tmp/test.c: In function 'main':
/tmp/test.c:4: error: lvalue required as left operand of assignment
/tmp/test.c:4: error: expected ';' before 'return'
$ g++ -o /tmp/test /tmp/test.cc
$

The world is insane. Luckily Gazelle will be the sword in your right hand, your weapon against a world that conspires against your sanity.

Incidentally, it’s more and more clear that C++ is not a superset of C. Though it’s true enough that most people using the language don’t have to care, for language implementors the differences are significant.

Sunday 18 January 2009

Rounding Algorithms

There are a zillion different ways to round floating point values to integers. C and C++ provide a couple basic ones in or .
There are two general categories of rounding algorithm: those that are symmetric about zero and those that are biased in some way.

Biased Rounding
A bias is a mathematical notion used in statistics to indicate that samples are not exactly representative of their true values; they are skewed in one way or another.

For example, the floor() function is biased towards negative infinity, because it always chooses the lower integer number --that is, it always chooses the number closer to negative infinity.

floor( 7.5 ) --> 7
floor( -7.5 ) --> -8


Suppose your local big city and wanted to know how fast people are driving on a particular freeway. The first step is to gather the exact speeds that individual drivers are going, and the second would be to convert all the individual values into a single value that would represent the normal rate of speed. For simplicity here, we will just use the average value.

Let us say that the equipment which samples a motorist's speed is far more accurate than the computer's ability to store it. (This is actually not uncommon.) Again, for simplicity, we will say that the computer stores the speed as integers.

With a sampling of twelve motorists, we get the following speeds (in miles per hour)

49.087 57.901 28.500 46.738 51.270 53.096
44.795 47.218 46.347 45.989 47.582 50.563

A quick calculation shows that the average speed is 47.424 mph.

If the city were to simply use the floor() function to convert these to integers, it would get

49 57 28 46 51 53
44 47 46 45 47 50

which averages to 46.916 --> 46 mph (remember, integer arithmetic!)

Either way, the sampling is off by about a whole mile per hour. I don't think that the city would actually care about a single mile per hour, but this does illustrate the bias, or tendancy of the floor() function, to make the numbers closer to negative infinity, thuse skewing the data to an inaccurate number.

This was just a simple example that came off the top of my head, but in many sciences and statistical surveys, that difference can mean quite a lot. Suppose that the Apollo missed the moon by 1%? Suppose a pharmaceutical company put too much iron in a daily vitamin pill by 1%? Suppose a construction firm miscalculated the stresses a bridge can take by 1%? In all these scenarios the results would prove deadly. One percent is a lot.


Symmetric Rounding
A special case of bias is centered about zero. Let us fix the floor() function to tend towards zero.
1
2
3
4
5
6
7
 

double floor0( double value )
  {
  if (value < 0.0)
  return ceil( value );
  else
  return floor( value );
  }


Now, the absolute value of the result will always be the same:

floor0( -7.7 ) --> -7 floor0( 7.7 ) --> 7
floor0( -7.5 ) --> -7 floor0( 7.5 ) --> 7
floor0( -7.3 ) --> -7 floor0( 7.3 ) --> 7

Enough about that.


Unbiased Rounding
So, how do we handle these biases? By adding some rule that accounts for it.

Let us apply knowledge we all learned in gradeschool: In arithmetic rounding we round up if the next digit is 5 or more, and if it less than 5 we round down. We write ourselves a little function to do just that:
1
2
3
4
 

double round( double value )
  {
  return floor( value + 0.5 );
  }


The problem is that this is still biased. We have actually reversed the bias of floor() from negative infinity to positive infinity, because we always choose to round up when exactly halfway between two values:

round( 10.3 ) --> 10
round( 10.5 ) --> 11
round( 10.7 ) --> 11

You can actually see the bias in the above table: the result tends towards 11 and away from 10.

This brings us to the trick: which way do we round when exactly halfway between two values?

One very popular method is variously called "bankers rounding", "round to even", "convergent rounding", and even "unbiased rounding", to name a few. It works by skewing the bias itself.

Given a number exactly halfway between two values, round to the even value (zero is considered even here).

round( 1.7 ) --> 2 round( 2.7 ) --> 3
round( 1.5 ) --> 2 round( 2.5 ) --> 2
round( 1.3 ) --> 1 round( 2.3 ) --> 2

For random data this is very convenient. Bankers like it because money deposited and withdrawn is random. (There are trends, mind you, but you cannot predict exactly how much will be deposited and withdrawn.) The important point is that the bankers rounding is still biased if the data is biased. It is only unbiased with random data.

One solution is called "alternate rounding". It works by simply choosing to bias up or down every other time.

round( 1.5 ) --> 2
round( 1.5 ) --> 1
round( 1.5 ) --> 2
round( 1.5 ) --> 1
etc

This is not always useful though.

The only way to eliminate all bias is to use a random bias... This, of course, is impossible to generate in your typical PC, but it still goes toward solving the problem quite nicely.

If the sample is exactly halfway between two integers, it chooses one or the other randomly.

Of course, the Achilles heel of this method is the random number generator you use. The default pseudorandom generator for C and C++ is not that great. The Mersenne Twister is by far the most popular high-quality pseudorandom number generator, but it is non-trivial to implement so I will not include it below.

Anyway, what follows is a convenient, simple library you are free to use. I'll even permit you to cannabalize it at will (since the algorithms are so obvious...)

I may update it sometime in the future if I can figure out a way around the default epsilon issue. Feel free to make suggestions for improvements.

:-)

Friday 16 January 2009

Review of Mastering C++

Mastering C++ is a book written by K. R. Venugopal, T Ravishankar and Rajkumar. The book teaches the computer language C++ from the scratch to the professional level in a very friendly approach to the learning of the otherwise very difficult language.

First published in 1997, the book is recommended by most of the programmers. Basically written with C programmers in mind, this book caters to novices as well.

My brother advised me to read this book as I was desperately trying to learn the language but was unable to do so. At the first sight of the book, I thought,” This book can’t help anyone. This is just another book for engineers and is full of technical jargon.”

Almost two years later I learned ‘C’ language from the book “Let Us C” by Yashwant Kanetkar.
That book helped me clear the basic concepts of programming and get some technical jargon of computers, giving me the break I needed.

I learned the concepts of OOPs from the reference books of NIIT. After that, I was ready to learn C++ in detail. I started from chapter-one which helped me get acquainted with thinking in terms of OOPs. And the following chapters till chapter nine taught me the basics of C++ (non-OOPs) and from 10 to 19 the OOPs side of the language. Chapter 20 was based on the management of software projects.

So after learning it, I decided to write some programs and got disappointed because I could write only console based programs, as standard C++ does not specify the platform independent GUI programming.

Though Mastering C++ is good for learning, to gain expertise in language one must not rely on this book alone. Specialized books in the field of data structures, network programming, games development etc should also be read and kept as reference.

But as far as the question of the language is concerned, this book can be trusted as it teaches the language and its constructs in details. To become expert in any field the base should be firm. And this book does the job.

Best of luck for your adventures in C++.

Thursday 15 January 2009

Two Reasons Why I Prefer C to Java

There are two specific reasons why I prefer C++ to Java: operator overloading and pointers. I strongly believe that these are related to the fact that I started learning C++ first, but I still find them critical to my preference for C++.

Operator overloading, for me, is a critical feature in C++ for providing intuitive code. When creating a mathematical class, such as BigInt, I want to be able to work with variables of that type the same way I work with variables of type int. If + is a meaningful operation on a class, I want to be able to use it. Moreover, I don't want to have to wrap my built-in type int in a class with .add(), .minus(), etc methods so that I can create a template for building rational numbers. I realize that this is a side-effect of my math background, but I believe that I should be able to write math with math symbols wherever possible.

The other irritation I have with Java is that it weakened pointers as found in languages like C++ and Pascal to what it calls a "reference". Anyone who is familiar with pointers in other languages will recognize that Java is using the pointer concept, but weakening it to make the language safer. I realize that this is a deliberate design decision, but it is a decision that irritates me in its implementation. It is both less function than C++ pointers, and more powerful in that it handles garbage collection. For me, losing pointer arithmetic for garbage collection is a bad trade
.

C++ Sets

The C++ Set is an associative STL container that contains a sorted set of unique objects.

Constructorsdefault methods to allocate, copy, and deallocate sets
Operatorsassign and compare sets
beginreturns an iterator to the beginning of the set
clearremoves all elements from the set
countreturns the number of elements matching a certain key
emptytrue if the set has no elements
endreturns an iterator just past the last element of a set
equal_rangereturns iterators to the first and just past the last elements matching a specific key
eraseremoves elements from a set
findreturns an iterator to specific elements
insertinsert items into a set
key_compreturns the function that compares keys
lower_boundreturns an iterator to the first element greater than or equal to a certain value
max_sizereturns the maximum number of elements that the set can hold
rbeginreturns a reverse_iterator to the end of the set
rendreturns a reverse_iterator to the beginning of the set
sizereturns the number of items in the set
swapswap the contents of this set with another
upper_boundreturns an iterator to the first element greater than a certain value
value_compreturns the function that compares values

Tuesday 13 January 2009

Insertion Sort Implementation in C++ [Sorting Algorithms]

Insertion Sort is sorting algorithm similar to Bubble Sort simply because they are basic sorting algorithms. The difference, is that Insertion Sort iterates through the data structure selects an element and inserts it into its correct location until no elements are left to sort.

Insertion Sort Visual Example

26 5 12 -6




First Iteration
The element 5 in position 1 is inserted into its appropriate location (position 0).

5 26 12 -6

26 vs 5 equals SWAP

Second Iteration
The element 26 in position 2 is inserted into its appropriate location (position 1).

5 12 26 -6

26 > 12 equals SWAP

Third Iteration
The element 26 in position 3 is in its appropriate position since it is greater than all the elements before it.

5 12 26 -6

12 <>

Fourth Iteration
The element -6 in position 3 is inserted into its appropriate position (position 0).

5 12 -6 26

26 > -6 SWAP

5 -6 12 26

12 > -6 SWAP

-6 5 12 26

5 > -6 SWAP

Saturday 10 January 2009

Polymorphism

Before getting into this section, it is recommended that you have a proper understanding of pointers and class inheritance. If any of the following statements seem strange to you, you should review the indicated sections:

Statement:
Explained in:
int a::b(c) {};
Classes
a->b
Data Structures
class a: public b;
Friendship and inheritance

Pointers to base class

One of the key features of derived classes is that a pointer to a derived class is type-compatible with a pointer to its base class. Polymorphism is the art of taking advantage of this simple but powerful and versatile feature, that brings Object Oriented Methodologies to its full potential.

We are going to start by rewriting our program about the rectangle and the triangle of the previous section taking into consideration this pointer compatibility property:

// pointers to base class
#include
using namespace std;

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

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

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

int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout << rect.area() << endl;
cout << trgl.area() << endl;
return 0;
}
20
10

In function main, we create two pointers that point to objects of class CPolygon (ppoly1 and ppoly2). Then we assign references to rect and trgl to these pointers, and because both are objects of classes derived from CPolygon, both are valid assignations.

The only limitation in using *ppoly1 and *ppoly2 instead of rect and trgl is that both *ppoly1 and *ppoly2 are of type CPolygon* and therefore we can only use these pointers to refer to the members that CRectangle and CTriangle inherit from CPolygon. For that reason when we call the area() members at the end of the program we have had to use directly the objects rect and trgl instead of the pointers *ppoly1 and *ppoly2.

In order to use area() with the pointers to class CPolygon, this member should also have been declared in the class CPolygon, and not only in its derived classes, but the problem is that CRectangle and CTriangle implement different versions of area, therefore we cannot implement it in the base class. This is when virtual members become handy:

Virtual members

A member of a class that can be redefined in its derived classes is known as a virtual member. In order to declare a member of a class as virtual, we must precede its declaration with the keyword virtual:
// virtual members
#include
using namespace std;

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

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

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

int main () {
CRectangle rect;
CTriangle trgl;
CPolygon poly;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
CPolygon * ppoly3 = &poly;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly3->set_values (4,5);
cout <<>area() << endl;
cout <<>area() << endl;
cout <<>area() << endl;
return 0;
}
20
10
0

Now the three classes (CPolygon, CRectangle and CTriangle) have all the same members: width, height, set_values() and area().

The member function area() has been declared as virtual in the base class because it is later redefined in each derived class. You can verify if you want that if you remove this virtual keyword from the declaration of area() within CPolygon, and then you run the program the result will be 0 for the three polygons instead of 20, 10 and 0. That is because instead of calling the corresponding area() function for each object (CRectangle::area(), CTriangle::area() and CPolygon::area(), respectively), CPolygon::area() will be called in all cases since the calls are via a pointer whose type is CPolygon*.

Therefore, what the virtual keyword does is to allow a member of a derived class with the same name as one in the base class to be appropriately called from a pointer, and more precisely when the type of the pointer is a pointer to the base class but is pointing to an object of the derived class, as in the above example.

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

Note that despite of its virtuality, we have also been able to declare an object of type CPolygon and to call its own area() function, which always returns 0.

Abstract base classes

Abstract base classes are something very similar to our CPolygon class of our previous example. The only difference is that in our previous example we have defined a valid area() function with a minimal functionality for objects that were of class CPolygon (like the object poly), whereas in an abstract base classes we could leave that area() member function without implementation at all. This is done by appending =0 (equal to zero) to the function declaration.

An abstract base CPolygon class could look like this:

// abstract class CPolygon
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area () =0;
};

Notice how we appended =0 to virtual int area () instead of specifying an implementation for the function. This type of function is called a pure virtual function, and all classes that contain at least one pure virtual function are abstract base classes.

The main difference between an abstract base class and a regular polymorphic class is that because in abstract base classes at least one of its members lacks implementation we cannot create instances (objects) of it.

But a class that cannot instantiate objects is not totally useless. We can create pointers to it and take advantage of all its polymorphic abilities. Therefore a declaration like:

CPolygon poly;

would not be valid for the abstract base class we have just declared, because tries to instantiate an object. Nevertheless, the following pointers:

CPolygon * ppoly1;
CPolygon * ppoly2;

would be perfectly valid.

This is so for as long as CPolygon includes a pure virtual function and therefore it's an abstract base class. However, pointers to this abstract base class can be used to point to objects of derived classes.

Here you have the complete example:

// abstract base class
#include
using namespace std;

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

class CRectangle: public CPolygon {
public:
int area (void)
{ return (width * height); }
};

class CTriangle: public CPolygon {
public:
int area (void)
{ return (width * height / 2); }
};

int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout <<>area() << endl;
cout <<>area() << endl;
return 0;
}
20
10

If you review the program you will notice that we refer to objects of different but related classes using a unique type of pointer (CPolygon*). This can be tremendously useful. For example, now we can create a function member of the abstract base class CPolygon that is able to print on screen the result of the area() function even though CPolygon itself has no implementation for this function:

// pure virtual members can be called
// from the abstract base class
#include
using namespace std;

class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area (void) =0;
void printarea (void)
{ cout << this->area() << endl; }
};

class CRectangle: public CPolygon {
public:
int area (void)
{ return (width * height); }
};

class CTriangle: public CPolygon {
public:
int area (void)
{ return (width * height / 2); }
};

int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly1->printarea();
ppoly2->printarea();
return 0;
}
20
10

Virtual members and abstract classes grant C++ the polymorphic characteristics that make object-oriented programming such a useful instrument in big projects. Of course, we have seen very simple uses of these features, but these features can be applied to arrays of objects or dynamically allocated objects.

Let's end with the same example again, but this time with objects that are dynamically allocated:

// dynamic allocation and polymorphism
#include
using namespace std;

class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area (void) =0;
void printarea (void)
{ cout << this->area() << endl; }
};

class CRectangle: public CPolygon {
public:
int area (void)
{ return (width * height); }
};

class CTriangle: public CPolygon {
public:
int area (void)
{ return (width * height / 2); }
};

int main () {
CPolygon * ppoly1 = new CRectangle;
CPolygon * ppoly2 = new CTriangle;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly1->printarea();
ppoly2->printarea();
delete ppoly1;
delete ppoly2;
return 0;
}
20
10

Notice that the ppoly pointers:

CPolygon * ppoly1 = new CRectangle;
CPolygon * ppoly2 = new CTriangle;
are declared being of type pointer to CPolygon but the objects dynamically allocated have been declared having the derived class type directly.