Sie sind auf Seite 1von 17

Pointers, Virtual Functions and Polymorphism

Pointers in C/C++
Pointers are variables that contain memory addresses (see Addresses, Pointers, and
References). They are an essential data type in C and C++, and are used for the following:
 Array variables are pointers and pointers can be used as alternative to subscripts.
 Dynamic memory allocation/deallocation returns a pointer to the allocated memory.
 For efficiency by passing the address of an object instead of copying the object to a
function. Reference parameters typically used.
 For function parameters that will be changed by the function
(out or inout parameters). Reference parameters typically used.

Declaring a pointer
Pointers are declared to point to a particular datatype. A "*" is written after the type to
indicate that this is a pointer to that type. For example, a pointer to an int would be
declared like this.
int* ip; // declares ip to be a pointer to an int.
You will also see variations in the spacing such as
int *ip;
int * ip;

NULL
NULL is the pointer to nothing, and should be used as the initial value for pointers because
using NULL will cause an error in most systems.

Pointer operators: * (dereference), & (address of), and arithmetic


Two operators are used when dealing with memory addresses:
 Unary & gives the address of (pointer to) something.
 Unary * takes the contents of a pointer (dereferences a pointer).
 Integers can be added to pointers, in which case they are first multiplied by the
element size
 Two pointers may be subtracted to yield an integer.

Example
char* cp; // declare pointer to char
char c, d; // declare char variables

cp = &c; // puts address of c into cp


c = 'x'; // assigns 'x' to c
*cp = 'x'; // also assigns 'x' to c
d = *cp; // copies c's value to d
cp = &d; // puts address of d into cp
*cp = c; // puts value of c into d

C++ Virtual Function

A virtual function is a member function in base class that you expect to redefine in derived
classes.

Before going into detail, let's build an intuition on why virtual functions are needed in the first
place.

An Example to Begin With


Let us assume, we are working on a game (weapons specifically).

We created the Weapon class and derived two classes Bomb and Gun to load features of respective
weapons.

#include <iostream>
using namespace std;

class Weapon
{
public:
void loadFeatures()
{ cout << "Loading weapon features.\n"; }
};

class Bomb : public Weapon


{
public:
void loadFeatures()
{ cout << "Loading bomb features.\n"; }
};
class Gun : public Weapon
{
public:
void loadFeatures()
{ cout << "Loading gun features.\n"; }
};

int main()
{
Weapon *w = new Weapon;
Bomb *b = new Bomb;
Gun *g = new Gun;

w->loadFeatures();
b->loadFeatures();
g->loadFeatures();

return 0;
}

Output

Loading weapon features.

Loading bomb features.

Loading gun features.

We defined three pointer objects w, b and g of classes Weapon, Bomb and Gun respectively. And,
we called loadFeatures() member function of each objects using:

w->loadFeatures();
b->loadFeatures();

g->loadFeatures();

Works perfectly!

However, our game project started getting bigger and bigger. And, we decided to create a
separate Loader class to load weapon features.

This Loader class loads additional features of a weapon depending on which weapon is
selected.

class Loader
{
public:
void loadFeatures(Weapon *weapon)
{
weapon->features();
}
};

The loadFeatures() loads the feature of a specific weapon.

Let's try to implement our Loader class


#include <iostream>
using namespace std;

class Weapon
{
public:
Weapon() { cout << "Loading weapon features.\n"; }

void features()
{ cout << "Loading weapon features.\n"; }
};

class Bomb : public Weapon


{
public:
void features()
{
this->Weapon::features();
cout << "Loading bomb features.\n";
}
};

class Gun : public Weapon


{
public:
void features()
{
this->Weapon::features();
cout << "Loading gun features.\n";
}
};

class Loader
{
public:
void loadFeatures(Weapon *weapon)
{
weapon->features();
}
};

int main()
{
Loader *l = new Loader;
Weapon *w;
Bomb b;
Gun g;

w = &b;
l->loadFeatures(w);

w = &g;
l->loadFeatures(w);

return 0;
}

Output

Loading weapon features.

Loading weapon features.

Loading weapon features.

Loading weapon features.

Our implementation seemed correct. However, weapon features was loaded 4 times. Why?

Initially, the Weapon object w is pointing to the b object (of Bomb) class. And, we tried to load the
features of Bomb object by passing it to loadFeatures()function using l object to pointer (of
Loader class).

Similarly, we tried to load the features of Gun object.

However, the loadFeatures() function of the Loader class takes pointer to object of
a Weapon class as an argument:
void loadFeatures(Weapon *weapon)

That's the reason weapon features are loaded 4 times. To solve this issue, we need to make
function of base class (Weapon class) virtual using virtual keyword.

class Weapon
{
public:
virtual void features()
{ cout << "Loading weapon features.\n"; }
};

Example: Using Virtual Function to Solve the Problem


#include <iostream>
using namespace std;

class Weapon
{
public:
virtual void features()
{ cout << "Loading weapon features.\n"; }
};

class Bomb : public Weapon


{
public:
void features()
{ this->Weapon::features();
cout << "Loading bomb features.\n";
}
};
class Gun : public Weapon
{
public:
void features()
{
this->Weapon::features();
cout << "Loading gun features.\n";
}
};

class Loader
{
public:
void loadFeatures(Weapon *weapon)
{
weapon->features();
}
};

int main()
{
Loader *l = new Loader;
Weapon *w;
Bomb b;
Gun g;

w = &b;
l->loadFeatures(w);

w = &g;
l->loadFeatures(w);

return 0;
}

Output

Loading weapon features.

Loading bomb features.

Loading weapon features.

Loading gun features.

Also, notice that, the l->loadFeatures(w) function calls the function of different classes
depending upon what l object is pointing.

Using virtual function made our code not only clearer but flexible too.

In the above program, weapon features is printed twice. We encourage you to add additional
code on the above program to load weapon features only once.

If we want to add another weapon (let's say knife), we can easily add and load features of
it. How?

class Knife : public Weapon


{
public:
void features()
{
this->Weapon::features();
cout << "Loading knife features.\n";
}
};

And, in main() function.

Knife k;
w = &k;

l->loadFeatures(w);

It's worth noticing that we didn't change anything in the Loader class to load features of knife.

C++ Abstract class and Pure virtual Function


The goal of object-oriented programming is to divide a complex problem into small sets. This
helps understand and work with problem in an efficient way.

Sometimes, it's desirable to use inheritance just for the case of better visualization of the
problem.

In C++, you can create an abstract class that cannot be instantiated (you cannot create object of
that class). However, you can derive a class from it and instantiate object of the derived class.

Abstract classes are the base class which cannot be instantiated.

A class containing pure virtual function is known as abstract class.

Pure Virtual Function


A virtual function whose declaration ends with =0 is called a pure virtual function. For example,

class Weapon

public:

virtual void features() = 0;

};
Here, the pure virtual function is

virtual void features() = 0

And, the class Weapon is an abstract class.

Example: Abstract Class and Pure Virtual Function


#include <iostream>
using namespace std;

// Abstract class
class Shape
{
protected:
float l;
public:
void getData()
{
cin >> l;
}

// virtual Function
virtual float calculateArea() = 0;
};

class Square : public Shape


{
public:
float calculateArea()
{ return l*l; }
};
class Circle : public Shape
{
public:
float calculateArea()
{ return 3.14*l*l; }
};

int main()
{
Square s;
Circle c;

cout << "Enter length to calculate the area of a square: ";


s.getData();
cout<<"Area of square: " << s.calculateArea();
cout<<"\nEnter radius to calculate the area of a circle: ";
c.getData();
cout << "Area of circle: " << c.calculateArea();

return 0;
}

Output

Enter length to calculate the area of a square: 4

Area of square: 16

Enter radius to calculate the area of a circle: 5

Area of circle: 78.5

In this program, pure virtual function virtual float area() = 0; is defined inside
the Shape class.
One important thing to note is that, you should override the pure virtual function of the base
class in the derived class. If you fail the override it, the derived class will become an abstract
class as well.

: Introduction – C++ Streams –

C does not have built-in input/output facilities. Instead, it left the I/O to the compiler as external
library functions (such as printf and scanf) in stdio (standard input output) library. The ANSI C
standard formalized these IO functions into Standard IO package (stdio.h). Likewise, C++
continues this approach and formalizes IO in iostream and fstream libraries.

Features of I/O in C++


 C++ IO is type safe.
 C++ IO operations are based on streams of bytes and are device independent.

Streams in C++
C++ IO is based on streams, which are a sequence of bytes flowing in and out of the programs
(just like water and oil flowing through a pipe). I/O systems in C++ are designed to work with a
wide variety of devices including terminals, disks and tape drives. The input-output system
supplies an interface to the programmer that is independent of the actual device being
accessed. This interface is known as a stream. A stream is a sequence of bytes which acts
either as a source from which input data can be obtained or as a destination to which output
data can be sent. The source stream which provides data to the program is called the input
stream and the destination stream which receives output from the program is called the output
stream.

To perform input and output, a C++ program must follow the steps mentioned below:

 Construct a stream object.


 Connect (Associate) the stream object to an actual IO device
 Perform input/output operations on the stream, via the functions defined in the stream's public
interface in a device-independent manner.
 Disconnect (Dissociate) the stream to the actual IO device (e.g., close the file).
 Free the stream object.
Unformatted input/output operations
You have already used the cin and cout (pre-defined in iostream file) for input and output of data
of various types. This has been made possible by overloading the operators << and >> to
recognize all the basic C++ types.

 cin standard input stream


 cout standard output stream
Example:
#include <iostream>

using namespace std;

void main()

int g;

cin>>g;

cout << "Output is: "<< g;

put() and get() functions


The classes istream and ostream defines two member functions get() and put() respectively to
handle single character input/output operations.

Get() function is of two types:

1. get(char *)
2. get(void)

Both of them can be used to fetch a character including a blank space, tab or new-line
character.

Code snippet
char ch;

cin.get(ch);

while(ch != '\n')

cout<<ch;

cin.get(ch);

Similarly, the function put(), a member of ostream class can be used to output a line of text
character by character.

Example:
cout.put ('g');

char ch;

cout.put(ch);

getline() and write()


You can read and display lines of text more efficiently using the lie oriented input/output
functions. They are:

 getline()
 write()

The getline() function reads the entire line of texts that ends with a newline character. The
general form of getline() is:

cin.getline (line, size);

The write() function displays the entire line of text and the general form of writing this function is:

cout.write (line, size);


Manipulators are operators used in C++ for formatting output. The data is manipulated by the
programmer's choice of display.

Some of the more commonly used manipulators are given below:

endl Manipulator
endl is the line feed operator in C++. It acts as a stream manipulator whose purpose is to feed
the whole line and then point the cursor to the beginning of the next line. We can use \n (\n is an
escape sequence) instead of endl for the same purpose.

setw Manipulator
This manipulator sets the minimum field width on output.

Syntax:
setw(x)

Example:

/*

* File: main.cpp

* Author: Gautam

* Created on October 16, 2011, 12:58 PM

*/#include <iostream>

#include <iomanip>

using namespace std;

int main() {

float basic, ta,da,gs;

basic=10000; ta=800; da=5000;


gs=basic+ta+da;

cout<<setw(10)<<"Basic"<<setw(10)<<basic<<endl

<<setw(10)<<"TA"<<setw(10)<<ta<<endl

<<setw(10)<<"DA"<<setw(10)<<da<<endl

<<setw(10)<<"GS"<<setw(10)<<gs<<endl;

return 0;

Program Output:

Das könnte Ihnen auch gefallen