1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14.

Thursday, August 27, 2009

Examples of local and global variables:

Examples of local and global variables:

1.
int a; // now 'a' value is 0 (default global value is 0)
main()
{
void f1() ;
printf("%d \n", a) ;
a++ ;
f1() ;
printf("%d \n", a) ;
}
void f1( )
{
printf("%d \n", a);
a++;
}

o/p:

0
1
2
From the above ,if global variable is modified in main() changes are visible in f1() and vice-versa. In general if global variable is modified in a function, changes are visible in rest of program.

NOTE:
Global variable is lost when program terminates but not function terminates

2. very important example for global and local variables work out this

int a= 1; // global variable intialisation
main()
{
auto int a =10;
void f1();
f1(); // 1st one
printf("%d \n", a); // 11th one
getch(); // 12th one
}
void f1()
{
auto int a = 100;
void f2();
f2(); // 2nd one
printf("%d \n", a); //9th one
a++; // 10th one
}
void f2()
{
void f3();
printf("%d \n", a); // 3rd one
a++; // 4th one
f3(); // 5th one
printf("%d \n", a); // 7th one
a++; // 8th one
}
void f3()
{
auto int a =1000;
printf("%d \n", a); // 6th one
}

NOTE:

1 // global value
10 // local to main
100 // local variable to f1
1000 // local variable to f3
Use functional key F7 for line by line execution

o/p:

1
1000
2
100
10

From the above , the comments in the program that is 1st one , 2nd one ...... these comments shows about flow of program execution, press F7 for line by line execution.

Examples of local and global variable

Examples of local and global variable:

int a = 1; // global variable
main()
{
printf("%d\n", a);
a++;
{
int a = 10;
printf("%d\n", a);
a++;
{
printf("%d\n", a);
a++;
}
printf("%d\n", a);
a++;
}
printf("%d", a);
getch();
}

o/p:
1
10
11
12
2

From the above, if variable of inner block does not exist, variable of the outer block is accessed in the inner block.We can declare a variable after any opening braces ( { ), it is lost when corresponding closing braces ( }) is reached.

Typical Questions In C Part-1

Differences between Memory and Register variables :

Memory variable :

  • It is declared by int a =10
  • Accessing memory is fast but not as fast as register
  • Memory is away from CPU
  • Memory variable have addresses , eg: int a; printf("%u",&a);
  • Memory is cheap every computer contain too many memory locations

Register variable :

  • It is declared by register int a = 10
  • CPU can access register data faster than memory data
  • Registers are part of CPU
  • Register variable have no addresses , eg: register int a; printf("%u", &a); // error
  • Registers are costly every computer contains handful of registers

Differences between local and global variables:

Local or automatic variable:

  • It is declared by auto int a = 10 or int a = 10, auto is default scope
  • It is declared inside the function
  • If it is not intialised garbage value is stored
  • It is created when function is called and lost when function terminates
  • It can be accessed in only one function, the function where it is declared
  • It is visible to one function only
  • It can be accessed by only one function, so data sharing is not possible
  • Parameter passing is required i.e., we can access local variable in different function by sending it as parameters in the function call
  • If value of local variable is modified in function , changes are not visible in rest of program
Global variable:
  • It is declared by int a =10
  • It is declared outside the function
  • If it is not initialized , 0 is stored by default
  • It is created before execution starts and lost when program terminates
  • It can be accessed more than one function
  • It is visible to entire program
  • It is accessed by multiple functions so data sharing is possible
  • Parameters passing is not required since global variable can be accessed throughout the program( without sending it as parameter to any function)
  • If value of global variable is modify in a function changes are visible in rest of program

NULL POINTER:
For example:
int a = 25;
int *p1 = &a; // p1 points to variable 'a'
int *p2 = NULL;
int *p3; // It points to somewhere in memory
int *p4 = -1; // error
From the above example, NULL indicates the pointer points to no variable, NULL is a predefined macro in stdio.h ( # define NULL 0)

P1 points to variable 'a' , p2 points to no variable, since it is initialize to NULL, P3 points somewhere in memory, P3 contains garbage address. A pointer can be initialize to address or NULL but not be the value

25 -----> integer
10.8f ------> float
'g' ------> char
NULL is pointer, P! P2 P3 are pointer variables, NULL is a pointer constant

Register variable :

  • It is declared by register int a = 10
  • CPU can access register data faster than memory data
  • Registers are part of CPU
  • Register variable have no addresses , eg: register int a; printf("%u", &a); // error
  • Registers are costly every computer contains handful of registers
Examples of Register variables:

1.
register int i;
for(i=1;i<=10;i++)
printf("%d\n", i);
If a variable is accessed more frequently in program declare as register variable, program execution is fast . Store more frequently accessed data in the register

2.
register float a =10.8; // error
We can store only integer data in registers, turboc is an exception

3.
register int a; //error
main()
{
-----
-----
}
Register variable must be declare inside the function like auto variable ( local variable)

4.
register long a =100000;
Let length of register be 2 bytes but long variable is 4 bytes then we use 2 registers for storing long value

5.
register int a , b , c , d , e , f , g;
Let there be 5 registers in the computer but 7 variables are declared as register variables, excess variables automatically becomes memory variables, inspite of writing register thus we can declare every variable in the program as register variable.When registers are exhausted , remaining variables are treated as memory variables

6.
register int a;
scanf("%d",&a); // error
Scanf demands & but register variable have no addresses hence we cannot read data into register variable

7.
register int a;
int b;
scanf("%d ", &b);
a = b; // store memory variable into register variable
Read value into memory variable by calling scanf() function, use = operator to copy the data from memory variable to register variable

How we can use storage classes in a program:

main()
{
auto int a =10;
static int b = 20;
extern int c;
register int d = 30;
register static int e = 40;
}
int c = 50;
static int f = 60;
f1()
{
-----
-----
}

Extern:
int a;
main()
{
extern int b;
}
f1()
{
------
------
}
int b;
f2()
{
------
------
}
f3()
{
-------
-------
}
printf("%d\n", a);
getch();
}

From the above a variable is global from the point of declaration till end of the program, 'a' is global to all the 4 functions, 'b' is global to f2(), f3() functions only, we cannot access global variable 'b' in the preceeding functions main() and f1().

Use extern to access global variable in the preceeding functions. Extern int b informs compiler that treat that as global to main() as well, thus 'b' is global to main(), f2() and f3(). New variable is not created due to extern.The global variable created else where is used in main() by extern. If extern is ommited local variable 'b' is created.

NOTE:
extern int b; This is global variable declaration, no memory is allocated, no variable is created.

eg:
1.
extern int b = 35; // error
We cannot initialize the variable since no variable is created
2.extern int b;
b= 35; // correct
Global variable 'b' is modified to '35' . If global variable is declared in middle of the program, it can be accessed in the following functions.Use extern to access it in the preceeding functions.
3.
main()
{
extern int a; // error
}
f1()
{
int a;
}
From the above , extern is only for global variable but not for local.To use extern the variable must be global elsewhere.

eg:
/* file 1.c */

extern int a;
void f2()
{
----
----
}
void f3()
{
-----
-----
}

/* file 2.c */

#include " file 1.c" // this includes the file1.c
int a;
main()
{
------
------
}
void f1()
{
------
------
}
From the above 'a' is global function in file 2.c. We can use the same global variable in a different file ( file 1.c) by using extern. Thus 'a' is global to 2 files. Program is divided into 2 files, it is a single program.

eg:
int a;
main()
{
-----
-----
}
f1()
{
-----
-----
}
From the above global variable of 1 program cannot be accessed in a different program. Global variable is lost when program terminates, hence it cannot be accessed in the
other program.


Tuesday, August 25, 2009

C++ Tutorial For C users

is that inside every derived class definition all methods the sort function needs are correctly defined:


#include &ltiostream.h>
#include &ltmath.h>

class octopus
{
public:

virtual double module() = 0; // = 0 implies function is not
// defined. This makes instances
// of this class cannot be declared.
};

double biggest_module (octopus &a, octopus &b, octopus &c)
{
double r = a.module();
if (b.module() > r) r = b.module();
if (c.module() > r) r = c.module();
return r;
}

class vector: public octopus
{
public:

double x;
double y;

vector (double a = 0, double b = 0)
{
x = a;
y = b;
}

double module()
{
return sqrt (x * x + y * y);
}
};

class number: public octopus
{
public:

double n;

number (double a = 0)
{
n = a;
}

double module()
{
if (n >= 0) return n;
else return -n;
}
};

void main ()
{
vector k (1,2), m (6,7), n (100, 0);
number p (5), q (-3), r (-150);

cout << biggest_module (k, m, n) << endl;
cout << biggest_module (p, q, r) << endl;

cout << biggest_module (p, q, n) << endl;
}



Perhaps you think "okay, that's a good idea to derive classes from the class octopus because that way I can apply to instances of my classes methods and function that were designed a generic way for the octopus class. But what if there exists another base class, named cuttlefish, which has very interesting methods and functions too? Do I have to make my choice between octopus and cuttlefish when I want to derive a class?" No, of course. A derived class can be at the same time derived from octopus and from cuttlefish. That's POLYMORPHISM. The derived class simply has to define the methods necessary for octopus together with the methods necessary for cuttlefish:

class octopus
{
virtual double module() = 0;
};

class cuttlefish
{
virtual int test() = 0;
};

class vector: public octopus, public cuttlefish
{
double x;
double y;

double module ()
{
return sqrt (x * x + y * y);
}

int test ()
{
if (x > y) return 1;
else return 0;
}
}



28
Probably you wonder what all those public: keywords mean. They mean the variables or the methods below them may be accessed and used everywhere in the program.

If you want them to be accessible only to methods of the class AND to methods of derived classes then you must put the keyword protected: above them.

If you want variables or methods be accessible ONLY to methods of the class then you must put the keyword private: above them.

The fact variables or methods are declared private or protected means no function external to the class may access or use them. That's ENCAPSULATION. If you want to give to a specific function the right to access those variables and methods then you must include that function's prototype inside the class definition, preceded by the keyword friend.

29
Now let's talk about input/output. In C++ that's a very broad subject.

Here is a program that writes to a file:

#include &ltiostream.h>
#include &ltfstream.h>

void main ()
{
fstream f;

f.open("c:\\test.txt", ios::out);

f << "This is a text output to a file." << endl;

double a = 345;

f << "A number: " << a << endl;

f.close();
}


Here is a program that reads from a file:

#include &ltiostream.h>
#include &ltfstream.h>

void main ()
{
fstream f;
char c;

cout << "What's inside the test.txt file from";
cout << "the C: hard disk root " << endl;
cout << endl;

f.open("c:\\test.txt", ios::in);

while (! f.eof() )
{
f.get(c); // Or c = f.get()
cout << c;
}

f.close();
}


30
Roughly said, it is possible to do on character arrays the same operations as on files. This is very useful to convert data or manage memory arrays.

Here is a program that writes inside a character array:


#include &ltiostream.h>
#include &ltstrstrea.h>
#include &ltstring.h>
#include &ltmath.h>

void main ()
{
char a[1024];
ostrstream b(a, 1024);

b.seekp(0); // Start from first char.
b << "2 + 2 = " << 2 + 2 << ends; // ( ends, not endl )
// ends is simply the
// null character '\0'
cout << a << endl;

double v = 2;

strcpy (a, "A sinus: ");

b.seekp(strlen (a));
b << "sin (" << v << ") = " << sin(v) << ends;

cout << a << endl;
}


A program that reads from a character string:

#include &ltiostream.h>
#include &ltstrstrea.h>
#include &ltstring.h>

void main ()
{
char a[1024];
istrstream b(a, 1024);

strcpy (a, "45.656");

double k, p;

b.seekg(0); // Start from first character.
b >> k;

k = k + 1;

cout << k << endl;

strcpy (a, "444.23 56.89");

b.seekg(0);
b >> k >> p;

cout << k << ", " << p + 1 << endl;
}



31
This program performs formated output two different ways. Please note the width() and setw() MODIFIERS are only effective on the next item output to the stream. The second next item will not be influenced.


#include &ltiostream.h>
#include &ltiomanip.h>

void main ()
{
int i;

cout << "A list of numbers:" << endl;
for (i = 1; i <= 1024; i *= 2)
{
cout.width (7);
cout << i << endl;
}

cout << "A table of numbers:" << endl;
for (i = 0; i <= 4; i++)
{
cout << setw(3) << i << setw(5) << i * i * i << endl;
}
}



You now have a basic knowledge about C++. Inside good books you will learn many more things. The file management system is very powerful, it has many other possibilities than those illustrated here. There is also a lot more to say about classes: template classes, virtual classes...
In order to work correctly with C++ you will need a good reference book, just like you need one for C. You will also need information on how C++ is used in your particular domain of activity. The standards, the global approach, the tricks, the typical problems encountered and their solutions... The best reference is of course the book written by Bjarn Stroustrup himself. Following book contains almost every detail about C and C++ and is constructed a way similar to this text:

C++ Tutorial For C users

double surface()
{
return x * y;
}
};

class trivector: public vector // trivector is derived from vector
{
public:
double z; // added to x and y from vector

trivector (double m=0, double n=0, double p=0): vector (m, n)
{
z = p; // Vector constructor will
} // be called before trivector
// constructor, with parameters
// m and n.

trivector (vector a) // What to do if a vector is
{ // cast to a trivector
x = a.x;
y = a.y;
z = 0;
}

double module () // define module() for trivector
{
return sqrt (x*x + y*y + z*z);
}

double volume ()
{
return this->surface() * z; // or x * y * z
}
};

void main()
{
vector a (4, 5);
trivector b (1, 2, 3);

cout << "a (4, 5) b (1, 2, 3) *r = b" << endl << endl;

cout << "Surface of a: " << a.surface() << endl;
cout << "Volume of b: " << b.volume() << endl;
cout << "Surface of base of b: " << b.surface() << endl;

cout << "Module of a: " << a.module() << endl;
cout << "Module of b: " << b.module() << endl;
cout << "Module of base of b: " << b.vector::module() << endl;

trivector k;
k = a; // thanks to trivector(vector) definition
// copy of x and y, k.z = 0
vector j;
j = b; // copy of x and y. b.z leaved out

vector *r;
r = &b;

cout << "Surface of r: " <<>surface() << endl;
cout << "Module of r: " <<>module() << endl;
}



25
In the program above, r->module() calculates the vector module, using x and y, because r has been declared a vector pointer. The fact r actually points towards a trivector is not taken into account. If you want the program to check the type of the pointed object and choose the appropriate method, then you must declare that method virtual inside the base class.

(If at least one of the methods of the base class is virtual then a "header" of 4 bytes is added to every instance of the classes. This allows the program to determine towards what a vector actually points.)

#include &ltiostream.h>
#include &ltmath.h>

class vector
{
public:

double x;
double y;

vector (double a = 0, double b = 0)
{
x = a;
y = b;
}

virtual double module()
{
return sqrt (x*x + y*y);
}
};

class trivector: public vector
{
public:
double z;

trivector (double m = 0, double n = 0, double p = 0)
{
x = m; // Just for the game,
y = n; // here I do not call the vector
z = p; // constructor and I make the
} // trivector constructor do the
// whole job. Same result.

double module ()
{
return sqrt (x*x + y*y + z*z);
}
};

void test (vector &k)
{
cout << "Test result: " << k.module() << endl;
}

void main()
{
vector a (4, 5);
trivector b (1, 2, 3);

cout << "a (4, 5) b (1, 2, 3)" << endl << endl;

vector *r;

r = &a;
cout << "module of vector a: " <<>module() << endl;

r = &b;
cout << "module of trivector b: " <<>module() << endl;

test (a);

test (b);

vector &s = b;

cout << "module of trivector b: " << s.module() << endl;
}


26
Maybe you wonder if a class can be derived from more than one base class. Answer is yes:


#include &ltiostream.h>
#include &ltmath.h>

class vector
{
public:

double x;
double y;

vector (double a = 0, double b = 0)
{
x = a;
y = b;
}

double surface()
{
return fabs (x * y);
}
};

class number
{
public:

double z;

number (double a)
{
z = a;
}

int is_negative ()
{
if (z < 0) return 1;
else return 0;
}
};

class trivector: public vector, public number
{
public:

trivector(double a=0, double b=0, double c=0): vector(a,b), number(c)
{
} // The trivector constructor calls the vector
// constructor, then the number constructor,
// and in this example does nothing more.

double volume()
{
return fabs (x * y * z);
}
};

void main()
{
trivector a(2, 3, -4);

cout << a.volume() << endl;
cout << a.surface() << endl;
cout << a.is_negative() << endl;
}


27
Class derivation allows to construct "more complicated" classes build above other classes. There is another application of class derivation: allow the programmer to write generic functions.

Suppose you define a base class with no variables. It makes no sense to use instances of that class inside your program. But you write a function whose purpose is to sort instances of that class. Well, that function will be able to sort any types of objects provided they belong to a class derived from that base class! The only condition

C++ Tutorial For C users

+ a + (b - a) * 7;
c = -c;

cout << "The module of vector c: " << c.module() << endl;

cout << "The content of vector a: " << a << endl;
cout << "The oposite of vector a: " << -a << endl;

c.set_length(2); // Transforms c in a vector of size 2.

a = vector (56, -3);
b = vector (7, c.y);

b.set_length(); // Transforms b in an unitary vector.

cout << "The content of vector b: " << b << endl;

double k;
k = vector(1, 1).module(); // k will contain 1.4142.
cout << "k contains: " << k << endl;
}



It is also possible to define the sum of vectors without mentioning it inside the vector class definition. Then it will not be a method of the class vector. Just a function that uses vectors:

vector operator + (vector a, vector b)
{
return vector (a.x + b.x, a.y + b.y);
}



In the example above of a full class definition, the multiplication of a vector by a double is defined. Suppose we want the multiplication of a double by a vector be defined too. Then we must write an isolated function outside the class:


vector operator * (double a, vector b)
{
return vector (a * b.x, a * b.y);
}



Of course the keywords new and delete work for class instances too. What's more, new automatically calls the constructor in order to initialize the objects, and delete automatically calls the destructor before deallocating the zone of memory the instance variables take:


#include &ltiostream.h>
#include &ltmath.h>

class vector
{
public:

double x;
double y;

vector (double = 0, double = 0);

vector operator + (vector);
vector operator - (vector);
vector operator - ();
vector operator * (double);
double module();
void set_length (double = 1);
};

vector::vector (double a, double b)
{
x = a;
y = b;
}

vector vector::operator + (vector a)
{
return vector (x + a.x, y + a.y);
}

vector vector::operator - (vector a)
{
return vector (x - a.x, y - a.y);
}

vector vector::operator - ()
{
return vector (-x, -y);

}

vector vector::operator * (double a)
{
return vector (a * x, a * y);
}

double vector::module()
{
return sqrt (x * x + y * y);
}

void vector::set_length (double a)
{
vector &the_vector = *this;

double length = the_vector.module();

x = x / length * a;
y = y / length * a;
}

ostream& operator << (ostream& o, vector a)
{
o << "(" << a.x << ", " << a.y << ")";
return o;
}

void main ()
{
vector c (3, 5);

vector *r; // r is a pointer to a vector.

r = new vector; // new allocates the memory necessary
cout << *r << endl; // to hold a vectors' variable,
// calls the constructor who will
// initialize it to 0, 0. Then finally
// new returns the address of the vector.

r->x = 94;
r->y = 345;
cout << *r << endl;

*r = vector (94, 343);
cout << *r << endl;

*r = *r - c;
r->set_length(3);
cout << *r << endl;

*r = (-c * 3 + -*r * 4) * 5;
cout << *r << endl;

delete r; // Calls the vector destructor then
// frees the memory.

r = &c; // r points towards vector c
cout << *r << endl;

r = new vector (78, 345); // Creates a new vector.
cout << *r << endl; // The constructor will initialise
// the vector's x and y at 78 and 345

cout << "x component of r: " <<>x << endl;
cout << "x component of r: " << (*r).x << endl;

delete r;

r = new vector[4]; // creates an array of 4 vectors

r[3] = vector (4, 5);
cout << r[3].module() << endl;

delete [] r; // deletes the array

int n = 5;
r = new vector[n]; // Cute!

r[1] = vector (432, 3);
cout << r[1] << endl;

delete [] r;

}


22
A class' variable can be declared static. Then only one instance of that variable exists, shared by all instances of the class:


#include &ltiostream.h>

class vector
{
public:

double x;
double y;
static int count;

vector (double a = 0, double b = 0)
{
x = a;
y = b;
count = count + 1;
}

~vector()
{
count = count - 1;
}
};

void main ()
{
vector::count = 0;

cout << "Number of vectors:" << endl;

vector a;
cout << vector::count << endl;

vector b;
cout << vector::count << endl;

vector *r, *u;

r = new vector;
cout << vector::count << endl;

u = new vector;
cout << a.count << endl;

delete r;
cout << vector::count << endl;

delete u;
cout << b.count << endl;
}


23
A class variable can also be constant. That's just like static, except it is alocated a value inside the class declaration and that value may not be modified:



#include &ltiostream.h>

class vector
{
public:

double x;
double y;
const double pi = 3.1415927;

vector (double a = 0, double b = 0)
{
x = a;
y = b;
}

double cilinder_volume ()
{
return x * x / 4 * pi * y;
}
};

void main(void)
{
cout << "The value of pi: " << vector::pi << endl << endl;

vector k (3, 4);

cout << "Result: " << k.cilinder_volume() << endl;
}


24
A class can be DERIVED from another class. The new class INHERITS the variables and methods of the BASE CLASS. Additional variables and/or methods can be added:

#include &ltiostream.h>
#include &ltmath.h>

class vector
{
public:

double x;
double y;

vector (double a = 0, double b = 0)
{
x = a;
y = b;
}

double module()
{
return sqrt (x*x + y*y);
}

C++ Tutorial For C users

<< endl;

person a;
cout << a.name << ", age " << a.age << endl << endl;

person b ("John");
cout << b.name << ", age " << b.age << endl << endl;

b.age = 21;
cout << b.name << ", age " << b.age << endl << endl;

person c ("Miki", 45);
cout << c.name << ", age " << c.age << endl << endl;

cout << "Bye!" << endl << endl;
}


Here is a short example of an array class definition. A method that is an overload of the [] operator and that outputs a reference (&) is used in order to generate an error if it is tried to access outside the limits of an array:

#include &ltiostream.h>
#include &ltstdlib.h>

class array
{
public:
int size;
double *data;

array (int s)
{
size = s;
data = new double [s];
}

~array ()
{
delete [] data;
}

double &operator [] (int i)
{
if (i <>= size)
{
cerr << endl << "Out of bounds" << endl;
exit (EXIT_FAILURE);
}
else return data [i];
}
};

void main ()
{
array t (5);

t[0] = 45; // OK
t[4] = t[0] + 6; // OK
cout << t[4] << endl; // OK

t[10] = 7; // error!
}



17
If you cast an object like a vector, everything will happen all right. For example if vector k contains (4, 7), after the cast m = k the vector m will contain (4, 7) too. Now suppose you're playing with objects like the person class above. If you cast such person object p, r by writing p = r it is necesary that some function does the necessary work to make p be a correct copy of r. Otherwise the result will be catastrophic; a mess of pointers and lost data. The method that will do that job is the COPY CONSTRUCTOR:

#include &ltiostream.h>
#include &ltstring.h>

class person
{
public:

char *name;
int age;

person (char *n = "no name", int a = 0)
{
name = new char[100];
strcpy (name, n);
age = a;
}

person (person &s) // The COPY CONSTRUCTOR
{
strcpy (name, s.name);
age = s.age;
}

~person ()
{
delete [] name;
}
};

void main ()
{
person p;
cout << p.name << ", age " << p.age << endl << endl;

person k ("John", 56);
cout << k.name << ", age " << k.age << endl << endl;

p = k;
cout << p.name << ", age " << p.age << endl << endl;

p = person ("Bob", 10);
cout << p.name << ", age " << p.age << endl << endl;
}



The copy constructor also allows your program to make copies of instances when doing calculations. It is a key method. During calculations instances are created to hold intermediate results. They are modified, casted and destroyed without you being aware.
In all the examples above the methods are defined inside the class definition. That makes them automatically be inline methods.

18
If a method cannot be inline, if you do not want it to be inline or if you want the class definition contain the minimum of information, then you must just put the prototype of the method inside the class and define the method below the class:


#include &ltiostream.h>

class vector
{
public:

double x;
double y;

double surface(); // The ; and no {} shows it is a prototype
};

double vector::surface()
{
double s = 0;

for (double i = 0; i < x; i++)
{
s = s + y;
}

return s;
}

void main ()
{
vector k;

k.x = 4;
k.y = 5;

cout << "Surface: " << k.surface() << endl;
}


19
When a method is applied to an instance, that method may use the instance's variables, modify them... But sometimes it is necessary to know the address of the instance. No problem, the keyword "this" is intended therefore:

#include &ltiostream.h>
#include &ltmath.h>

class vector
{
public:

double x;
double y;

vector (double a = 0, double b = 0)
{
x = a;
y = b;
}

double module()
{
return sqrt (x * x + y * y);
}

void set_length (double a = 1)
{
double length;

length = this->module();

x = x / length * a;
y = y / length * a;
}
};

void main ()
{
vector c (3, 5);

cout << "The module of vector c: " << c.module() << endl;

c.set_length(2); // Transforms c in a vector of size 2.

cout << "The module of vector c: " << c.module() << endl;

c.set_length(); // Transforms b in an unitary vector.

cout << "The module of vector c: " << c.module() << endl;
}


20
Of course it is possible to declare arrays of objects:

#include &ltiostream.h>
#include &ltmath.h>

class vector
{
public:

double x;
double y;

vector (double a = 0, double b = 0)
{
x = a;
y = b;
}

double module ()
{
return sqrt (x * x + y * y);
}
};

void main ()
{
vector s[1000];

vector t[3] = {vector(4, 5), vector(5, 5), vector(2, 4)};

s[23] = t[2];

cout << t[0].module() << endl;
}


21
Here is an example of a full class declaration:

#include &ltiostream.h>
#include &ltmath.h>

class vector
{
public:

double x;
double y;

vector (double = 0, double = 0);

vector operator + (vector);
vector operator - (vector);
vector operator - ();
vector operator * (double a);
double module();
void set_length (double = 1);
};

vector::vector (double a, double b)
{
x = a;
y = b;
}

vector vector::operator + (vector a)
{
return vector (x + a.x, y + a.y);
}

vector vector::operator - (vector a)
{
return vector (x - a.x, y - a.y);
}

vector vector::operator - ()
{
return vector (-x, -y);
}

vector vector::operator * (double a)
{
return vector (x * a, y * a);
}

double vector::module()
{
return sqrt (x * x + y * y);
}

void vector::set_length (double a)
{
double length = this->module();

x = x / length * a;
y = y / length * a;
}

ostream& operator << (ostream& o, vector a)
{
o << "(" << a.x << ", " << a.y << ")";
return o;
}

void main ()
{
vector a;
vector b;
vector c (3, 5);

a = c * 3;
a = b + c;
c = b - c

C++ Tutorial For C users

// the [] would deallocate the
// memory zone without destructing
// each of the 15 instances. That
// would cause memory leakage.

int n = 30;

d = new double[n]; // new can be used to allocate an
// array of random size.
for (int i = 0; i < s =" new">



15
What is a class? Well, that's a struct yet with more possibilities. METHODS can be defined. They are C++ functions dedicated to the class. Here is an example of such a class definition:


#include &ltiostream.h>

class vector
{
public:

double x;
double y;

double surface ()
{
double s;
s = x * y;
if (s < s =" -s;" x =" 3;" y =" 4;">


In the example above, a is an INSTANCE of the class "vector".
Just like a function, a method can be an overload of any C++ operator, have any number of parameters (yet one parameter is always implicit: the instance it acts upon), return any type of parameter, or return no parameter at all.

A method is allowed to change the variables of the instance it is acting upon:


#include &ltiostream.h>

class vector
{
public:

double x;
double y;

vector its_oposite()
{
vector r;

r.x = -x;
r.y = -y;

return r;
}

void be_oposited()
{
x = -x;
y = -y;
}

void be_calculated (double a, double b, double c, double d)
{
x = a - c;
y = b - d;
}

vector operator * (double a)
{
vector r;

r.x = x * a;
r.y = y * a;

return r;
}
};

void main (void)
{
vector a, b;

a.x = 3;
b.y = 5;

b = a.its_oposite();

cout << "Vector a: " << a =" b" a =" b.its_oposite()">

16
Very special and essential methods are the CONSTRUCTOR and DESTRUCTOR. They are automatically called whenever an instance of a class is created or destroyed (variable declaration, end of program, new, delete...).

The constructor will initialize the variables of the instance, do some calculation, allocate some memory for the instance, output some text... whatever is needed.

Here is an example of a class definition with two overloaded constructors:

#include &ltiostream.h>

class vector
{
public:

double x;
double y;

vector () // same name as class
{
x = 0;
y = 0;
}

vector (double a, double b)
{
x = a;
y = b;
}

};

void main ()
{
vector k; // vector () is called

cout << "vector k: " << k =" vector">


It is a good practice to try not to overload the constructors. Best is to declare only one constructor and give it default parameters wherever possible:


#include &ltiostream.h>

class vector
{
public:

double x;
double y;

vector (double a = 0, double b = 0)
{
x = a;
y = b;
}
};

void main ()
{
vector k;
cout << "vector k: " <<>


The destructor is often not necessary. You can use it to do some calculation whenever an instance is destroyed or output some text for debugging. But if variables of the instance point towards some allocated memory then the role of the destructor is essential: it must free that memory! Here is an example of such an application:

#include &ltiostream.h>
#include &ltstring.h>

class person
{
public:

char *name;
int age;

person (char *n = "no name", int a = 0)
{
name = new char[100]; // better than malloc!
strcpy (name, n);
age = a;
cout << "Instance initialized, 100 bytes allocated" <<>

C++Tutorial For C Users

double min (double a, double b). That does the job for the whole program.
Would you have tried something like calculating min (i1, d1) the compiler would have reported that as an error. Indeed the template tells both parameters are of the same type.

You can use a random number of different template data types in a template definition. And not all parameter types must be templates, some of them can be of standard types or user defined (char, int, double...). Here is an example where the min function takes parameters of any, possibly different, types and outputs a value that has the type of the first parameter:


#include &ltiostream.h>

template &ltclass type1, class type2>
type1 min (type1 a, type2 b)
{
type1 r, b_converted;
r = a;
b_converted = (type1) b;
if (b_converted < a) r = b_converted;
return r;
}

void main ()
{
int i;
double d;

i = 45;
d = 7.41;

cout << "Most little: " << min (i, d) << endl;
cout << "Most little: " << min (d, i) << endl;
cout << "Most little: " << min ('A', i) << endl;
}


14
The keywords new and delete can be used to allocate and deallocate memory. They are much more sweet than the functions malloc and free from standard C. new [] and delete [] are used for arrays:


#include &ltiostream.h>
#include &ltstring.h>

void main ()
{
double *d; // d is a variable whose purpose
// is to contain the address of a
// zone where a double is located


d = new double; // new allocates a zone of memory
// large enough to contain a double
// and returns its address.
// That address is stored in d.

*d = 45.3; // The number 45.3 is stored
// inside the memory zone
// whose address is given by d.

cout << "Type a number: ";
cin >> *d;

*d = *d + 5;

cout << "Result: " << *d << endl;

delete d; // delete deallocates the
// zone of memory whose address
// is given by pointer d.
// Now we can no more use that zone.


d = new double[15]; // allocates a zone for an array
// of 15 doubles. Note each 15
// double will be constructed.
// This is pointless here but it
// is vital when using a data type
// that needs its constructor be
// used for each instance.

d[0] = 4456;
d[1] = d[0] + 567;

cout << "Content of d[1]: " << d[1] << endl;

delete [] d; // delete [] will deallocate the
// memory zone. Note each 15
// double will be destructed.
// This is pointless here but it
// is vital when using a data type
// that needs its destructor be
// used for each instance (the ~
// method). Using delete without

C++Tutorial For C Users

return r;
else return s;
}

void main ()
{
double k = 3;
double m = 7;

cout << "k: " << k << endl;
cout << "m: " << m << endl;
cout << endl;

biggest (k, m) = 10;

cout << "k: " << k << endl;
cout << "m: " << m << endl;
cout << endl;

biggest (k, m) ++;

cout << "k: " << k << endl;
cout << "m: " << m << endl;
cout << endl;
}



Again, provided you're used at pointer arithmetics and if you wonder how the program above works, just think the compiler translated it into the following standard C program:


#include &ltiostream.h>

double *biggest (double *r, double *r)
{
if (*r > *s) return r;
else return s;
}

void main ()
{
double k = 3;
double m = 7;

cout << "k: " << k << endl;
cout << "m: " << m << endl;
cout << endl;

(*(biggest (&k, &m))) = 10;

cout << "k: " << k << endl;
cout << "m: " << m << endl;
cout << endl;

(*(biggest (&k, &m))) ++;

cout << "k: " << k << endl;
cout << "m: " << m << endl;
cout << endl;
}



To end with, for people who have to deal with pointers yet do not like it, references are very useful to un-pointer variables:


#include &ltiostream.h>

double *silly_function () // This function returns a pointer to a double
{
static double r = 342;
return &r;
}

void main()
{
double *a;

a = silly_function();

double &b = *a; // Now b IS the double towards which a points!

b += 1; // Great!
b = b * b; // No need to write *a everywhere!
b += 4;

cout << "Content of *a, b, r: " << b << endl;
}



8
If they contain just simple lines of code, use no for loops or the like, C++ functions can be declared inline. This means their code will be inserted right everywhere the function is used. That's somehow like a macro. Main advantage is the program will be faster. A little drawback is it will be bigger, because the full code of the function was inserted everywhere it is used:


#include &ltiostream.h>
#include &ltmath.h>

inline double hypothenuse (double a, double b)
{
return sqrt (a * a + b * b);
}

void main ()
{
double k = 6, m = 9;

// Next two lines produce exactly the same code:

cout << hypothenuse (k, m) << endl;
cout << sqrt (k * k + m * m) << endl;
}



9
You know the classical structures of C: for, if, do, while, switch... C++ adds one more structure named EXCEPTION:


#include &ltiostream.h>
#include &ltmath.h>

void main ()
{
int a, b;

cout << "Type a number: ";
cin >> a;
cout << endl;

try
{
if (a > 100) throw 100;
if (a < 10) throw 10;
throw a / 3;
}
catch (int result)
{
cout << "Result is: " << result << endl;
b = result + 1;
}

cout << "b contains: " << b << endl;

cout << endl;

// another example of exception use:

char zero[] = "zero";
char pair[] = "pair";
char notprime[] = "not prime";
char prime[] = "prime";

try
{
if (a == 0) throw zero;
if ((a / 2) * 2 == a) throw pair;
for (int i = 3; i <= sqrt (a); i++)
{
if ((a / i) * i == a) throw notprime;
}
throw prime;
}
catch (char *conclusion)
{
cout << "The number you typed is "<< conclusion << endl;
}

cout << endl;

}



10
It is possible to define default parameters for functions:

#include &ltiostream.h>

double test (double a, double b = 7)
{
return a - b;
}

void main ()
{
cout << test (14, 5) << endl;
cout << test (14) << endl;
}



11
One important advantage of C++ is the OPERATOR OVERLOAD. Different functions can have the same name provided something allows to distinguish between them: number of parameters, type of parameters...


#include &ltiostream.h>

double test (double a, double b)
{
return a + b;
}

int test (int a, int b)
{
return a - b;
}

void main ()
{
double m = 7, n = 4;
int k = 5, p = 3;

cout << test(m, n) << " , " << test(k, p) << endl;
}



12
The operators overload can be used to define the basic symbolic operators for new sorts of parameters:

#include &ltiostream.h>

struct vector
{
double x;
double y;
};

vector operator * (double a, vector b)
{
vector r;

r.x = a * b.x;
r.y = a * b.y;

return r;
}

void main ()
{
vector k, m; // No need to type "struct vector"

k.x = 2; // Keep cool, soon you'll be able
k.y = -1; // to write k = vector (45, -4).

m = 3.1415927 * k; // Magic!

cout << "(" << m.x << ", " << m.y << ")" << endl;
}



Besides multiplication, 43 other basic C++ operators can be overloaded, including +=, ++, the array [], and so on...
The operation cout << is an overload of the binary shift of integers. That way the << operator is used a completely different way. It is possible to overload the << operator for the output of vectors:


#include &ltiostream.h>

struct vector
{
double x;
double y;
};

ostream& operator << (ostream& o, vector a)
{
o << "(" << a.x << ", " << a.y << ")";
return o;
}

void main ()
{
vector a;

a.x = 35;
a.y = 23;

cout << a << endl;
}



13
Tired of defining five times the same function? One definition for int type parameters, one definition for double type parameters, one definition for float type parameters... Didn't you forget one type? What if a new data type is used? No problem: the C++ compiler is capable of generating automatically every version of the function that is necessary! Just tell him how the function looks like by declaring a template function:

#include &ltiostream.h>

template &ltclass ttype>
ttype min (ttype a, ttype b)
{
ttype r;

r = a;
if (b < a) r = b;

return r;
}

void main ()
{
int i1, i2, i3;

i1 = 34;
i2 = 6;
i3 = min (i1, i2);
cout << "Most little: " << i3 << endl;

double d1, d2, d3;

d1 = 7.9;
d2 = 32.1;
d3 = min (d1, d2);
cout << "Most little: " << d3 << endl;

cout << "Most little: " << min (d3, 3.5) << endl;
}



The function min is used three times in above program yet the C++ compiler generates only two versions of it: int min (int a, int b) and

C++ tutorial for C users

This text enunciates and illustrates features and basic principles of C++. It is aimed at experienced C users who wish to learn C++. It can also be interesting for C++ users who leaved out some possibilities of the language.


// for one-line remarks

Console input and output streams

Variable declarations can be put inside the code without using hooks

Variables can be initialised by a calculation involving other variables

Variables can be declared inside a for loop declaration

Global variables can be accessed even if a local variables has the same name

It is possible to declare a REFERENCE towards another variable

A function can be declared inline

The exception structure has been added

A functions can have default parameters

PARAMETERS OVERLOAD: several functions can be declared with the same name provided there is a difference in their parameters list

The symbolic operators (+ - * / ...) can be defined for new data types

Different functions for different data types will automatically be generated provided you define a template function

The keywords new and delete are much better to allocate and deallocate memory

A class is a struct upon which you can define METHODS

The CONSTRUCTOR and the DESTRUCTOR can be used to initialise and destroy an instance of a class

The COPY CONSTRUCTOR allows to define an appropriate = operator

The method bodies can be defined below the class definition

The keyword this is a pointer towards the instance a method is acting upon

Arrays of instances can be declared

An example of complete class declaration

static variables inside a class definition

const variables inside a class definition

A class can be DERIVED from another class

If a method is declared virtual the program will always first check the type of an instance that is pointed to and will use the appropriate method.

A class can be derived from more than one base class

Class derivation allows to write generic methods

ENCAPSULATION: public, protected and private

Brief examples of file I/O

Character arrays can be used like files

An example of formated output


1
You can use / / to type a remark:


#include &ltiostream.h> // This library is often used

void main () // The program's main routine.
{
double a; // Declaration of variable a.

a = 456;
a = a + a * 21.5 / 100; // A calculation.

cout << a; // Display the content of a.
}



2
Input from keyboard and output to screen can be performed through cout <<>>:


#include &ltiostream.h>

void main()
{
int a; // a is an integer variable
char s [100]; // s points to a sring of 99 characters

cout << "This is a sample program." << endl;

cout << endl; // Line feed (end of line)

cout << "Type your age : ";
cin >> a;

cout << "Type your name: ";
cin >> s;

cout << endl;

cout << "Hello " << s << " you're " << a << " old." << endl;
cout << endl << endl << "Bye!" << endl;
}



3
Variables can be declared everywhere inside the code without using hooks:


#include &ltiostream.h>

void main ()
{
double a;

cout << "Hello, this is a test program." << endl;

cout << "Type parameter a: ";
cin >> a;

a = (a + 1) / 2;

double c;

c = a * 5 + 1;

cout << "c contains : " << c << endl;

int i, j;

i = 0;
j = i + 1;

cout << "j contains : " << j << endl;
}


4
A variable can be initialised by a calculation involving other variables:


#include &ltiostream.h>

void main ()
{
double a = 12 * 3.25;
double b = a + 1.112;

cout << "a contains : " << a << endl;
cout << "b contains: " << b << endl;

a = a * 2 + b;

double c = a + b * a;

cout << "c contains: " << c << endl;
}



Like in C, variables can be encapsulated between hooks:


#include &ltiostream.h>

void main()
{
double a;

cout << "Type a number: ";
cin >> a;

{
int a = 1;
a = a * 10 + 4;
cout << "Local number: " << a << endl;
}

cout << "You typed: " << a << endl;
}



5
C++ allows to declare a variable inside the for loop declaration. It's like if the variable had been declared just before the loop:


#include &ltiostream.h>

void main ()
{
for (int i = 0; i < 4; i++)
{
cout << i << endl;
}

cout << "i contains: " << i << endl;

for (i = 0; i < 4; i++)
{
for (int i = 0; i < 4; i++) // we're between
{ // previous for's hooks
cout << i;
}
cout << endl;
}
}



6
A global variable can be accessed even if another variable with the same name has been declared inside the function:


#include &ltiostream.h>

double a = 128;

void main ()
{
double a = 256;

cout << "Local a: " << a << endl;
cout << "Global a: " <<::a << endl;
}



7
It is possible to make one variable be another:


#include &ltiostream.h>

void main ()
{
double a = 3.1415927;

double &b = a; // b IS a

b = 89;

cout << "a contains: " << a << endl; // Displays 89.
}



(If you are used at pointers and absolutely want to know what happens, simply think double &b = a is translated to double *b = &a and all subsequent b are replaced by *b.)

The value of REFERENCE b cannot be changed after its declaration. For example you cannot write, a few lines further, &b = c expecting now b IS c. It won't work.
Everything is said on the declaration line of b. Reference b and variable a are married on that line and nothing will separate them.

References can be used to allow a function to modify a calling variable:


#include &ltiostream.h>

void change (double &r, double s)
{
r = 100;
s = 200;
}

void main ()
{
double k, m;

k = 3;
m = 4;

change (k, m);

cout << k << ", " << m << endl; // Displays 100, 4.
}



If you are used at pointers in C and wonder how exactly the program above works, here is how the C++ compiler translates it (those who are not used at pointers, please skip this ugly piece of code):

#include &ltiostream.h>

void change (double *r, double s)
{
*r = 100;
s = 200;
}

void main ()
{
double k, m;

k = 3;
m = 4;

change (&k, m);

cout << k << ", " << m << endl; // Displays 100, 4.
}



A reference can be used to let a function return a variable:

#include &ltiostream.h>

double &biggest (double &r, double &s)
{
if (r > s)

Function Pointers

listMenu->add(new MenuItem('a', "Append data", Handler_app));

This line of code adds one menu item with label "Append data", key 'a' into the menu listMenu. Not only is this item created, but a function address is also associated with it, in this case the address of Handler_app. The menu subsystem registers this address in a function pointer in some internal data structure. Now the menu subsystem may use the function pointer to call Handler_app, when the user chooses the menu item "Append data". The menu subsystem module does not need to know anything about the frontend subsystem, and vice versa. A third module is needed however, one with the knowledge about the two. But this is good since the menu subsystem may very well be replaced by some other system without having to change the frontend, and vice versa. Wouldn't it be nice with a GUI with that list?

Neat, is it not? This method is known as the callback "paradigm". This is one of the most common way to abstract modules and make them less cohesive.

Function Pointers

Table of Contents
1.What are function pointers?
2.What advantages does this give me?
3.Example - Iterating through a list
-Example 1 - Code
-Example 2 - Code
-Example 3 - Code
4.Some useful tips for programmers
-Short hand notation
-Module abstraction and indepenence

What are function pointers?

Function pointers are means to add another level of indirection. Remember pointers to variables? Function pointers are no different.

Let's say that there are two identical functions a and b (by identical we mean that the functions have the same return type and the same parameter type). We also declare a function pointer p. The function pointer is defined such that it shares the same return type and parameter types as a and b. By assigning the address of a to p, p = a;, calls to p will in effect yield calls to a. Likewise, p can be assigned b, where calls to p yield calls to b. Getting dizzy yet? ;-)

Here's a very simple example which works with C and C++.

#include &ltstdio.h>

void a(void)
{
printf("a was called.\n");
}

void b(void)
{
printf("b was called.\n");
}

int main(void)
{
void (*p)(void); /* This is a function pointer declaration */

p = a;
(*p)(); /* Using function pointer p */
p = b;
(*p)(); /* Using function pointer p (again) */
return 0; /* Standard exit procedure in UNIX */
}


As you can see, the function pointer declaration looks somewhat complicated. The "standard remedy" for this is to create a new function pointer type by using the typedef operator.

Same example again using the typedef operator.

#include &ltstdio.h>

typedef void (*FuncType)(void); /* FuncType is a function pointer type */

void a(void)
{
printf("a was called.\n");
}

void b(void)
{
printf("b was called.\n");
}

int main(void)
{
FuncType p; /* This is a function pointer declaration */

p = a;
(*p)(); /* Using function pointer p */
p = b;
(*p)(); /* Using function pointer p (again) */
return 0; /* Standard exit procedure in UNIX */
}


What advantage does this give me?

As you probably learned in your first programming courses, pointers to variables allows you to modify variable contents from a non-local environment. This gives the flexibility of writing generic functions which do not alter "known" global variables, but references to "unknown" variables. Such functions can be reused. Function pointers gives you the same flexibility, but at a higher level. Instead of calling a "known" function, one can call any arbitrary "unknown" function. This is the main advantage of function pointers: greater flexibility and better code reuse.

Example - Iterating through a list

In this example I'll show a very common (and naive) solution for iterating through a list, then a somewhat "better" solution and last I'll show a general and resuable solution.

The list is a list of strings and we want to iterate it for printing to screen. As a twist, we also want to print out the a list of the string lengths rather than the strings.

Example 1 - Code:
This is a very naive implementation.

#include &ltstdio.h>

typedef struct ListRecord List;

struct ListRecord {
char* text;
List* next;
};

List* listInsert(List* list, const char* text)
{
ListRecord* rec;

rec = (ListRecord*)malloc(sizeof(ListRecord));
rec->text = strdup(text); /* Make a copy of string */
rec->next = list; /* Link in old list */
return list;
}

int main(void)
{
List* list;
ListRecord* i;

list = NULL;
list = listInsert(list, "World!");
list = listInsert(list, "Hello");

printf("List begins\n");
for(i = list; i != NULL; i = i->next)
printf("Text: %s\n", i->text);
printf("List ends\n");


printf("List begins (lengths)\n");
for(i = list; i != NULL; i = i->next)
printf("Text Length: %d\n", strlen(i->text));
printf("List ends\n");

return 0;
}


Example 2 - Code:
This is a better implementation. Functionality has been moved out into separate functions. printList and printListStrLen are new functions.

#include &ltstdio.h>

typedef struct ListRecord List;

struct ListRecord {
char* text;
List* next;
};

void printList(List* list)
{
ListRecord* i;

printf("List begins\n");
for(i = list; i != NULL; i = i->next)
printf("Text: %s\n", i->text);
printf("List ends\n");
}

void printListStrLen(List* list)
{
ListRecord* i;

printf("List begins (reversed)\n");
for(i = list; i != NULL; i = i->next)
printf("Text Length: %s\n", strlen(i->text));
printf("List ends\n");
}

List* listInsert(List* list, const char* text)
{
ListRecord* rec;

rec = (ListRecord*)malloc(sizeof(ListRecord));
rec->text = strdup(text); /* Make a copy of string */
rec->next = list; /* Link in old list */
return list;
}

int main(void)
{
List* list;

list = NULL;
list = listInsert(list, "World!");
list = listInsert(list, "Hello");

printList(list);
printListStrLen(list);

return 0;
}


Example 3 - Code:
This solution is the best of the three since it allows for high code reuse. It makes use of function pointers for performing the actual printing and it separates the "for-looping" into a function of its own. The three new key features in this example is ListRecordOperation, print, printStrLen and listForEach. Note that adding new features such as printing the text in reverse is now very easy. Just add a function that is compatible with the ListRecordOperation type and call listForEach with the function as argument. No more tedious moments of writing for-loops and such, now you can focus on the problem at hand instead.

#include &ltstdio.h>

typedef void (*ListRecordOperation)(const char*);

typedef struct ListRecord List;

struct ListRecord {
char* text;
List* next;
};

/* function compatible with ListRecordOperation */
void print(const char* text)
{
printf("Text: %s\n", text);
}

/* function compatible with ListRecordOperation */
void printStrLen(const char* text)
{
printf("Text Length: %s\n", strlen(text));
}

void listForEach(List* list, ListRecordOperation op)
{
ListRecord* i;

for(i = list; i != NULL; i = i->next)
(*op)(list->text); /* Calling whatever op points to with i->text
as argument */
}

List* listInsert(List* list, const char* text)
{
ListRecord* rec;

rec = (ListRecord*)malloc(sizeof(ListRecord));
rec->text = strdup(text); /* Make a copy of string */
rec->next = list; /* Link in old list */
return list;
}

int main(void)
{
List* list;

list = NULL;
list = listInsert(list, "World!");
list = listInsert(list, "Hello");

listForEach(list, print);
listForEach(list, printStrLen);

return 0;
}


Useful tips for programmers
Short hand notation
Function pointers may be used with a shorthand notation. Instead of dereferencing the function pointer with an asterisk:

p = a;
(*p)();


you can use it like this:

p = a;
p();


as if it was an "ordinary" function. Gives C an aesthetic appeal. ;-)

Module abstraction and indepenence
During the development phase of a project, the code is more or less always in a state of flux. Often, one wants to change the interface of some module so that it can serve some other modules needs better. Communication between modules may very well be done using function pointers. A prime example of this is the frontend.cpp and menu.cpp modules in the lab files (dsa-lab.tar). In fact this is the only way that the menu subsystem can call functions in the frontend module without having "intimate" knowledge them.

The code which creates the menu items looks like this:

C++ Debugging

assumptions your code makes on its environment and on other code/data, and thus it gives you the opportunity to develop better techniques and prevent bugs.
By placing assertions near the top of the function and/or right before and after their conditions are used, other programmers will be able to more easily prevent bugs in the way they use your code.
It helps to communicate the intent of your code, its affects on related functions/data, and any design limitations it might have.
Bugs are easier to track down when using assertions to check key parameters, because they are found when the arguments are passed into the function, not in some obscure algorithm or function down the road, or even worse, going undetected until they cause other errors.
It makes it easier to track incorrect return values (see assert( SUCCEEDED(hr) ) with DirectX) ;)
You don't have to think up exception descriptions or return value error codes, and this is helpful when you are simply writing new code and wish to test something quickly, and for painfully obvious stuff like assert( this ).
Method 2 - Exceptions
Pros: Automatic cleanup and elegant shutdown, opportunity to continue if handled, works in both debug and release builds

Cons: Relatively slow

Explanation
Basically, you use the throw keyword to throw data up to some unknown function caller and the stack continues to unwind (think of it like the program is reversing itself) until someone catches the data. You use the try keyword to enclose code that you'd like to catch exceptions from. See:

void some_function() { throw 5; } // some function that throws an exception

int main(int argc, char* argv[])
{
try // just letting the compiler know we want to catch any exceptions from this code
{
some_function();
}

catch(const int x) // if the type matches the data thrown, we execute this code
{
// do something about the exception...
}
}


If you don't place try blocks in your code, then the stack will simply continue to unwind until it gets past the main function, and your program will exit. You don't have to place them everywhere - only where you can catch an exception and can recover from it. If you can only recover from it partially, you can rethrow the original exception (by the empty throw statement "throw;") and the stack will continue unwinding until it hits the next matching catch block.

Examples
Exceptions are best used in key places in debug and release builds to track exceptional conditions. If used properly, they provide automatic cleanup and then either force the application to quit or put itself back into a valid state. Thus exceptions are perfect for release code, because they provide everything the end user wants in a well-behaved program that encounters unexpected errors. Correctly used, they provide the following benefits:

Automatic cleanup of all resources from any point in execution.
They force the app to either quit or put itself back into a valid state.
They force the recipient of the exception to handle it, instead of merely being optional (as with return values and assertions).
They allow the deallocation code to be written by the person who wrote the allocation code and be handled implicitly (destructors, of course!).
Because of the overhead, it is generally a bad idea to use them for normal flow control because other control structures will be faster and more efficient.

Method 3 - Return Values
Pros: Fast when used with built-in types and/or constants, allow a change in the client's logic and possible cleanup

Cons: Error-handling isn't mandatory, values could be confusing

Explanation
Basically, we either return valid data back to the caller, or a value to indicate an error:

const int divide(const int divisor, const int dividend)
{
if( dividend == 0 ) return( 0 ); // avoid "integer divide-by-zero" error

return( divisor/dividend );
}


A value of zero indicates that the function failed. Unfortunately, in this example you can also get a return value of zero by passing in zero for the divisor (which is perfectly valid), so the caller has no idea whether this function returned an error. This function is nonsensical, but it illustrates the problem of using return values for error handling. It's hard or impossible to choose error values for all functions.

Conclusion
Return values are best used in conditions when there is a grey area between an error and a simple change in logic. For example, a function might return a set of bit flags, some of which might be considered erroroneous by one client, and not by the other. Return values are great for conditional logic.

A function trusting a function caller to notice an error condition is like a lifeguard trusting other swimmers to notice someone who is drowning.

Method 4 - Logging
Sometimes you do not have access to a debugger, and logging errors to a file can be quite helpful in debugging. Declare a global log file (or use std::clog) and output text to it when an error occurs. It might also help to output the file name and line number so you can tell where the error occurred. __FILE__ and __LINE__ tell the compiler to insert the current filename and line number.

You can also use log files to record messages other than errors, such as the maximum number of matrices in use or some other such data that you can't access with a debugger. Or you could output the data that caused your function to fail, etc. std::fstream is great for this purpose. If you are really clever, you could figure out some way to make your assertions and exceptions log their messages to a file. :)

This provides the following benefits:

It's easy to integrate with your existing code and highly portable.
It can provide human-readable output in lieu of a debugger.
It can provide detailed information without interrupting the program.
Of course, it does have some overhead so you'll have to decide whether that is offset by the benefits in your situation.

One More Thing...
I had intended to finish this article here, but I wish to show how valuable a mixed approach to debugging can be. The easiest way to do this is by creating a simple class, preferrably one that must work with non-C++ code. A file class will do nicely. We'll use C's fopen() and related functions for simplicity and portability.

We need to meet the following requirements:

Constructor and destructor that match the lifetime of the file pointer.
Assertions to describe assumptions made by each function.
Exception types used to force the client to handle exceptional conditions.
Member functions for reading and writing data.
Templated member functions as shortcuts for stack-based data.
Exception safety, including a fail-safe destructor and responsible member functions.
Portability.
Here it is:

#include &ltcstdio>
#include &ltcassert>
#include &ltciso646>
#include &ltstring>

class file
{
public:

// Exceptions
struct exception {};
struct not_found : public exception {};
struct end : public exception {};

// Constants
enum modes { relative, absolute };

file(const std::string& filename, const std::string& parameters);
~file();

void seek(const unsigned int position, const enum modes = relative);
void read(void* const data, const unsigned int size);
void write(const void* const data, const unsigned int size);
void flush();

// Stack only!
template &lttypename T> void read(T& data) { read(&data, sizeof(data)); }
template &lttypename T> void write(const T& data) { write(&data, sizeof(data)); }

private:
FILE* pointer;

file(const file& other) {}
file& operator = (const file& other) { return( *this ); }
};


file::file(const std::string& filename, const std::string& parameters)
: pointer(0)
{
assert( not filename.empty() );
assert( not parameters.empty() );

pointer = fopen(filename.c_str(), parameters.c_str());

if( not pointer ) throw not_found();
}


file::~file()
{
int n = fclose(pointer);
assert( not n );
}


void file::seek(const unsigned int position, const enum file::modes mode)
{
int n = fseek(pointer, position, (mode == relative) ? SEEK_CUR : SEEK_SET);
assert( not n );
}


void file::read(void* const data, const unsigned int size)
{
size_t s = fread(data, size, 1, pointer);

if( s != 1 and feof(pointer) ) throw end();
assert( s == 1 );
}


void file::write(const void* const data, const unsigned int size)
{
size_t s = fwrite(data, size, 1, pointer);
assert( s == 1 );
}


void file::flush()
{
int n = fflush(pointer);
assert( not n );
}


int main(int argc, char* argv[])
{
file myfile("myfile.txt", "w+");

int x = 5, y = 10, z = 20;
float f = 1.5f, g = 29.4f, h = 0.0129f;
char c = 'I';

myfile.write(x);
myfile.write(y);
myfile.write(z);
myfile.write(f);
myfile.write(g);
myfile.write(h);
myfile.write(c);

return 0;
}


If you compile this under Windows, make sure the project type is set to "Win32 Console App." What benefits does this class provide to its clients?

It allows the user to manually debug in order to see which function and thus which parameters caused the member function to fail.
It checks all return values

 
# #