Sei sulla pagina 1di 8

Topics in this Note:

Void Pointers
Constructor and inheritance
Polymorphism, Virtual Functions and Abstract Class
Virtual Function and Polymorphism
Pure Virtual Function and Abstract Class

Void Pointers
The void pointer, also known as the generic pointer, is a special type of pointer that can be pointed at
objects of any data type! A void pointer is declared like a normal pointer, using the void keyword as the
pointer’s type:

1void *pVoid; // pVoid is a void pointer

A void pointer can point to objects of any data type:

1
2 int nValue;
3 float fValue;
4
struct Something
5 {
6 int nValue;
7 float fValue;
8 };
9
10Something sValue;
11
void *pVoid;
12pVoid = &nValue; // valid
13pVoid = &fValue; // valid
14pVoid = &sValue; // valid
15

However, because the void pointer does not know what type of object it is pointing to, it can not be
dereferenced! Rather, the void pointer must first be explicitly cast to another pointer type before it is
dereferenced.

1int nValue = 5;

2void *pVoid = &nValue;

3// can not dereference pVoid because it is a void pointer

4 int *pInt = static_cast<int*>(pVoid); // cast from void* to int*

5 cout << *pInt << endl; // can dereference pInt


6

Similarly, it is not possible to do pointer arithmetic on a void pointer. Note that since void pointers can’t be
dereferenced, there is no such thing as a void reference.

The next obvious questions is: If a void pointer doesn’t know what it’s pointing to, how do we know what to
cast it to? Ultimately, that is up to you to keep track of.

Here’s an example of a void pointer in use:

1 #include <iostream>

2 enum Type{

3 INT, FLOAT, STRING,};

void Print(void *pValue, Type eType)


4
{ using namespace std;
5
switch (eType)
6
{ case INT:
7
cout << *static_cast<int*>(pValue) << endl;
8
break;
9 case FLOAT:

10 cout << *static_cast<float*>(pValue) << endl;

11 break;

12 case STRING:

13 cout << static_cast<char*>(pValue) << endl;

break;
14
}
15
}
16
int main(){ int nValue = 5;
17
float fValue = 7.5;
18
char *szValue = "Mollie";
19
Print(&nValue, INT);
20
Print(&fValue, FLOAT);
21 Print(szValue, STRING);

22 return 0;}
This program prints:

5
7.5

Constructor and inheritance


The compiler automatically call a base class constructor before executing the derived class constructor. The
compiler’s default action is to call the default
constructor in the base class. If you want to specify which of several base class constructors should be called
during the creation of a derived class object.

In these cases, you must explicitly specify which base class constructor should be called by the compiler. This is
done by specifying the arguments to the selected base class constructor in the definition of the derived class
constructor.

class Rectangle

{
private :
float length;
float width;
public:
Rectangle ()
{
length = 0;
width = 0;
}

Rectangle (float len, float wid)


{
length = len;
width = wid;
}

float area()
{
return length * width ;
}
};

class Box : public Rectangle


{
private :
float height;
public:
Box ()
{
height = 0;
}

Box (float len, float wid, float ht) : Rectangle(len, wid)


{
height = ht;
}

float volume()
{
return area() * height;
}
};

int main ()
{
Box bx;
Box cx(4,8,5);
cout << bx.volume() << endl;
cout << cx.volume() << endl;
return 0;
}

output :

0
160

Overriding Base Class Functions

A derived class can override a member function of its base class by defining a derived class member function
with the same name and parameter list.
It is often useful for a derived class to define its own version of a member function inherited from its base class.
This may be done to specialize the member function to the needs of the derived class. When this happens, the
base class member function is said to be overridden by the derived class.

class mother
{
public:
void display ()
{
cout << "mother: display function\n";
}
};

class daughter : public mother


{
public:
void display ()
{
cout << "daughter: display function\n\n";
}
};

int main ()
{
daughter rita;
rita.display();
return 0;
}
output:

daughter: display function

Gaining Access to an Overridden Function

It is occasionally useful to be able to call the overridden version. This is done by using the scope resolution
operator to specify the class of the overridden member function being accessed.

class daughter : public mother

{
public:
void display ()
{
cout << "daughter: display function\n\n";
mother::display();
}
};

output:

daughter: display function

mother: display function


Virtual Base Class
Multipath inheritance may lead to duplication of inherited members from a grandparent
base class. This may be avoided by making the common base class a virtual base class.
When a class is made a virtual base class, C++ takes necessary care to see that only one
copy of that class is inherited.
class A
{ .....
.....
};

class B1 : virtual public A


{ .....
.....
};

class B2 : virtual public A


{ .....
.....
};
class C : public B1, public B2
{ .....// only one copy of A
.....// will be inherited };
Polymorphism, Virtual Functions and Abstract Class
In C++, a pointer variable of a base class type can point to an object of its derived class. There are situations
when this feature of C++ can be used to develop generic code for a variety of applications.

Pointer of base class


Consider the following program to understand pointer compatibility property

#include <iostream>

using namespace std;

class Shape
{
protected:
double width, height;
public:
void set_data (double a, double b)
{
width = a; height = b; } };

class Rectangle: public Shape


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

int main ()
{
Shape *sPtr; //declare pointer variables of type Shape
Rectangle Rect; //create the object rect of type Rectangle
sPtr = &Rect; //make sPtr point to the object rect.

sPtr->set_data (5,3); //set length and width of object rect


cout << sPtr -> area() << endl; //Compile Error !!

return 0;
}
Notice that even though rectPtr is poining to rect (object of type Rectangle), when the program executes, the
statement sets length and width of rectangle. If you tried to access area function of class Rectangle with sPtr it
will give you compiler error.
sPtr -> area()

is a compiler error !

It means base class pointer can not access the additional member function of its derived class. If we want
to do this we need to type cast the base class pointer.

Using Type Casts with Base Class Pointers


We can use a type cast to get the compiler to accept the statement:

static_cast <Rectangle *> (sPtr)->area()

so we should write the statment

cout << static_cast <Rectangle *> (sPtr) -> area() << endl;

The type cast informs the compiler that sPtr is actually pointing to a Rectangle object derived from the Shape
base class. In general, a pointer to a base class that actually points to a derived class object must first be
appropriately cast before the additional features of the derived class can be used.

Virtual Function and Polymorphism


Virtual functions are used in C++ to support polymorphic behavior. We are modifing the above program and
will introduce you the concept of virtual function by following example:

#include <iostream>
using namespace std;

class Shape
{
protected:
double width, height;
public:
void set_data (double a, double b)
{
width = a;
height = b;
}
virtual double area()
{return 0;}
};

class Rectangle: public Shape


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

int main ()
{
Shape *sPtr;
Rectangle Rect;
sPtr = &Rect;

sPtr -> set_data (5,3);


cout << sPtr -> area() << endl;

return 0;
}

Output :
15

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. The member
function area() has been declared as virtual in the base class because it is later redefined in each
derived class. The advantage of having virtual function is that we are able to access area function of
derived class by pointer variable of base class.

Pure Virtual Function and Abstract Class


In above example, base class Shape member function area do not need any implementation because it is
overriding in derived class. If this is the case, the C++ language permits the programmer to declare the function
a pure virtual function. The C++ way of declaring a pure virtual function is to put the expression = 0 in the class
declaration. For example, if a member function double area() is being declared pure virtual, then its declaration
in its class looks like

virtual double area() = 0;

A pure virtual function is sometimes called an abstract function, and a class with at least one pure virtual
function is called an abstract class. The C++ compiler will not allow you to instantiate an abstract class.
Abstract classes can only be subclassed: that is, you can only use them as base classes from which to derive
other classes.

A class derived from an abstract class inherits all functions in the base class, and will itself be an abstract class
unless it overrides all the abstract functions it inherits. The usefulness of abstract classes lies in the fact that they
define an interface that will then have to be supported by objects of all classes derived from it.

#include <iostream>
using namespace std;

class Shape
{
protected:
double width, height;
public:
void set_data (double a, double b)
{
width = a;
height = b;
}
virtual double area() = 0;
};
class Rectangle: public Shape
{
public:
double area () { return (width * height); } };

class Triangle: public Shape


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

int main ()
{
Shape *sPtr;

Rectangle Rect;
sPtr = &Rect;

sPtr -> set_data (5,3);


cout << "Area of Rectangle is " << sPtr -> area() << endl;

Triangle Tri;
sPtr = &Tri;

sPtr -> set_data (4,6);


cout << "Area of Triangle is " << sPtr -> area() << endl;
return 0;
}
Output :
Area of Rectangle is 15
Area of Triangle is 12

Potrebbero piacerti anche