it is by no means a complete c++ tutorial, but should give you a good idea of the power of c++.
In this tutorial, i will be using virtualisation, abstraction, and polymorphism to draw a simple picture.
the code is not complete, because i dont want to tie it into any specific operating system.
i will use onlt standard template library finctions, and graphics requires the use of OS specific API's/
We are going to write a program, which holds an array or different shapes.
and (if complete) would draw thenm ot the screen.. (for this example, the will just output somthing like "I am a circle, radius 12, x=20, y=50"
It doesnt sound impressive, but we will be using a single array to hold different classes without using a container. In other words, its like having an array that holds some integers, some booleans, and some strings. it is normally not allowed.
first, before the code, some simple definitions.
=============================
Virtual functions:
=============================
A virtual function is a function which apears to exist to some parts of the code, but aprears not to exist to other parts of the code.
a Pure virtual function is the same, but has no function body. if a class has at least one pure virtual function, then it is considered abstract. meaning it cannot be used directly, but can be used as a template for other functions.
Take a look at the following example program
CODE
#include<iostream>
using namespace std;
class base_class {
public:
[tab][/tab]void function1() {
cout << "function1 of base_class" << endl;
[tab][/tab]}
[tab][/tab]virtual void function2() {
cout << "function2 of base_class" << endl;
[tab][/tab]}
};
class sub_class : public base_class {
public:
[tab][/tab]void function2() {
cout << "function2 of sub_class" << endl;
[tab][/tab]}
};
class sub_class2 : public base_class {};
int main() {
[tab][/tab]base_class BASE;
[tab][/tab]sub_class SUB_A;
[tab][/tab]sub_class2 SUB_B;
[tab][/tab]BASE.function1(); // outputs "function1 of base_class"
[tab][/tab]BASE.function2(); // outputs "function2 of base_class"
[tab][/tab]
[tab][/tab]SUB_A.function1(); // outputs "function1 of base_class"
[tab][/tab]SUB_A.function2(); // outputs "function2 of sub_class"
[tab][/tab]
[tab][/tab]SUB_B.function1(); // outputs "function1 of base_class"
[tab][/tab]SUB_B.function2(); // outputs "function2 of base_class"
[tab][/tab]return 0;
}
using namespace std;
class base_class {
public:
[tab][/tab]void function1() {
cout << "function1 of base_class" << endl;
[tab][/tab]}
[tab][/tab]virtual void function2() {
cout << "function2 of base_class" << endl;
[tab][/tab]}
};
class sub_class : public base_class {
public:
[tab][/tab]void function2() {
cout << "function2 of sub_class" << endl;
[tab][/tab]}
};
class sub_class2 : public base_class {};
int main() {
[tab][/tab]base_class BASE;
[tab][/tab]sub_class SUB_A;
[tab][/tab]sub_class2 SUB_B;
[tab][/tab]BASE.function1(); // outputs "function1 of base_class"
[tab][/tab]BASE.function2(); // outputs "function2 of base_class"
[tab][/tab]
[tab][/tab]SUB_A.function1(); // outputs "function1 of base_class"
[tab][/tab]SUB_A.function2(); // outputs "function2 of sub_class"
[tab][/tab]
[tab][/tab]SUB_B.function1(); // outputs "function1 of base_class"
[tab][/tab]SUB_B.function2(); // outputs "function2 of base_class"
[tab][/tab]return 0;
}
virtual function2 in the base class apears to exist, except to the class sub_class, because this class defines its own function2, it over-rides the virtual function.
we could have made function2 a pure virtual function be declairing it like so....
CODE
virtual void function2() = 0;
a pure virtual function exists ONLY to be over-ridden.
you cannot declair an instance of a class containing pure virtual functions, and so if this had been the case, the line
CODE
base_class BASE;
would have caused a compile error.a class containing pure virtual functions is called abstract.
=============================
Polymorphic objects. (the clever pointer)
=============================
In C++, the pointer rules have been relaxed.
a pointer of type XYZ can point to any class derived from XYZ
the following code example is perfectly legal in c++
CODE
class commom{};
class tree : public common{};
class bird : public common{};
class car : public common{};
class pan_galactic_gargle_blaster : public common{};
int main() {
[tab][/tab]common* array[5];
[tab][/tab]
[tab][/tab]array[0] = new common;
[tab][/tab]array[1] = new tree;
[tab][/tab]array[2] = new bird;
[tab][/tab]array[3] = new car;
[tab][/tab]array[4] = new pan_galactic_gargle_blaster;
[tab][/tab]return 0;
}
class tree : public common{};
class bird : public common{};
class car : public common{};
class pan_galactic_gargle_blaster : public common{};
int main() {
[tab][/tab]common* array[5];
[tab][/tab]
[tab][/tab]array[0] = new common;
[tab][/tab]array[1] = new tree;
[tab][/tab]array[2] = new bird;
[tab][/tab]array[3] = new car;
[tab][/tab]array[4] = new pan_galactic_gargle_blaster;
[tab][/tab]return 0;
}
=====================================================
MAIN example, combining the 2 examples above.
======================================================
Armed with the ability to have an array of different types, and the ability to over ride functions,
we can do some very clever things.
we are going to write a simpe drawing program.
it will be an array of different shapes, the base class will have a draw() function
which draws different shapes, depending on how it is used. (polymorphic, to change shape! lol )
// include the usual stuff.
CODE
#include<iostream>
#include<vector>
using std::vector;
using std::cout;
using std::cin;
#include<vector>
using std::vector;
using std::cout;
using std::cin;
now we need our common base class
CODE
class shape {
protected:
[tab][/tab]int x_position;
[tab][/tab]int y_position;
[tab][/tab]int width;
[tab][/tab]int height;
public:
[tab][/tab]virtual void draw() = 0;
[tab][/tab]void setX(int x) {
x_position = x;
[tab][/tab]}
[tab][/tab]void setY(int y) {
y_position = y;
[tab][/tab]}
[tab][/tab]void setW(int w) {
width = w;
[tab][/tab]}
[tab][/tab]void setH(int h) {
height = h;
[tab][/tab]}
};
protected:
[tab][/tab]int x_position;
[tab][/tab]int y_position;
[tab][/tab]int width;
[tab][/tab]int height;
public:
[tab][/tab]virtual void draw() = 0;
[tab][/tab]void setX(int x) {
x_position = x;
[tab][/tab]}
[tab][/tab]void setY(int y) {
y_position = y;
[tab][/tab]}
[tab][/tab]void setW(int w) {
width = w;
[tab][/tab]}
[tab][/tab]void setH(int h) {
height = h;
[tab][/tab]}
};
This is ab abstract class because it contains a pure virtual function draw.
the size variables, and manipulation functions are common to all shapes, so they go in the base class.
now lets add some shapes/
CODE
class triangle : public shape {
public:
[tab][/tab]void draw() {
[tab][/tab]
cout << "i am a triangle" << endl;
cout << "[tab][/tab]height:" << height << endl;
cout << "[tab][/tab]width:" << width << endl;
cout << "[tab][/tab]X:" << x_position << endl;
cout << "[tab][/tab]Y:" << y_position << endl;
[tab][/tab]}
};
class circle : public shape {
public:
[tab][/tab]void draw() {
[tab][/tab]
cout << "i am a circle" << endl;
cout << "[tab][/tab]radius:" << height << endl;
cout << "[tab][/tab]X:" << x_position << endl;
cout << "[tab][/tab]Y:" << y_position << endl;
[tab][/tab]}
};
class rectangle : public shape {
public:
[tab][/tab]void draw() {
[tab][/tab]
cout << "i am a rectangle" << endl;
cout << "[tab][/tab]height:" << height << endl;
cout << "[tab][/tab]width:" << width << endl;
cout << "[tab][/tab]X:" << x_position << endl;
cout << "[tab][/tab]Y:" << y_position << endl;
[tab][/tab]}
};
class dot : public shape {
public:
[tab][/tab]void draw() {
[tab][/tab]
cout << "i am a dot" << endl;
cout << "[tab][/tab]X:" << x_position << endl;
cout << "[tab][/tab]Y:" << y_position << endl;
[tab][/tab]}
};
public:
[tab][/tab]void draw() {
[tab][/tab]
cout << "i am a triangle" << endl;
cout << "[tab][/tab]height:" << height << endl;
cout << "[tab][/tab]width:" << width << endl;
cout << "[tab][/tab]X:" << x_position << endl;
cout << "[tab][/tab]Y:" << y_position << endl;
[tab][/tab]}
};
class circle : public shape {
public:
[tab][/tab]void draw() {
[tab][/tab]
cout << "i am a circle" << endl;
cout << "[tab][/tab]radius:" << height << endl;
cout << "[tab][/tab]X:" << x_position << endl;
cout << "[tab][/tab]Y:" << y_position << endl;
[tab][/tab]}
};
class rectangle : public shape {
public:
[tab][/tab]void draw() {
[tab][/tab]
cout << "i am a rectangle" << endl;
cout << "[tab][/tab]height:" << height << endl;
cout << "[tab][/tab]width:" << width << endl;
cout << "[tab][/tab]X:" << x_position << endl;
cout << "[tab][/tab]Y:" << y_position << endl;
[tab][/tab]}
};
class dot : public shape {
public:
[tab][/tab]void draw() {
[tab][/tab]
cout << "i am a dot" << endl;
cout << "[tab][/tab]X:" << x_position << endl;
cout << "[tab][/tab]Y:" << y_position << endl;
[tab][/tab]}
};
each class needs to override the pure virtual function in the shape class.
if a class failed to override the draw() function, then that class would in turn become abstract.
finally, let se out super cool porgram in action.
CODE
int main() {
[tab][/tab]vector<shape*> shapes;
[tab][/tab]shapes.push_back( new triangle() );
[tab][/tab]shapes.push_back( new circle() );
[tab][/tab]shapes.push_back( new rectangle() );
[tab][/tab]shapes.push_back( new dot() );
[tab][/tab]shapes.push_back( new triangle() );
[tab][/tab]shapes.push_back( new circle() );
[tab][/tab]shapes.push_back( new rectangle() );
[tab][/tab]shapes.push_back( new dot() );
[tab][/tab]// set all the shapes member variables (idealy, use random)
[tab][/tab]for(int n=0; n< shapes.size(); n++) {
shapes[n]->setX(1);
shapes[n]->setY(2);
shapes[n]->setH(3);
shapes[n]->setW(4);
[tab][/tab]}
[tab][/tab]// draw the picture !
[tab][/tab]for(int n=0; n< shapes.size(); n++) {
shapes[n]->draw();
[tab][/tab]}
[tab][/tab]
// clean up, prevent memory leaks.
[tab][/tab]for(int n=0; n< shapes.size(); n++) {
delete shapes[n];
[tab][/tab]}
[tab][/tab]return 0;
}
[tab][/tab]vector<shape*> shapes;
[tab][/tab]shapes.push_back( new triangle() );
[tab][/tab]shapes.push_back( new circle() );
[tab][/tab]shapes.push_back( new rectangle() );
[tab][/tab]shapes.push_back( new dot() );
[tab][/tab]shapes.push_back( new triangle() );
[tab][/tab]shapes.push_back( new circle() );
[tab][/tab]shapes.push_back( new rectangle() );
[tab][/tab]shapes.push_back( new dot() );
[tab][/tab]// set all the shapes member variables (idealy, use random)
[tab][/tab]for(int n=0; n< shapes.size(); n++) {
shapes[n]->setX(1);
shapes[n]->setY(2);
shapes[n]->setH(3);
shapes[n]->setW(4);
[tab][/tab]}
[tab][/tab]// draw the picture !
[tab][/tab]for(int n=0; n< shapes.size(); n++) {
shapes[n]->draw();
[tab][/tab]}
[tab][/tab]
// clean up, prevent memory leaks.
[tab][/tab]for(int n=0; n< shapes.size(); n++) {
delete shapes[n];
[tab][/tab]}
[tab][/tab]return 0;
}
the vector MUST be a vector of pointers to shapes, and not a vector of shapes.
the the intelligent pointer that knows what functions to call.
and just for fun, the output of the compiled program.
QUOTE
bash-2.05b$ g++ TEST.cpp -o TEST
bash-2.05b$ ./TEST
i am a triangle
height:3
width:4
X:1
Y:2
i am a circle
radius:3
X:1
Y:2
i am a rectangle
height:3
width:4
X:1
Y:2
i am a dot
X:1
Y:2
i am a triangle
height:3
width:4
X:1
Y:2
i am a circle
radius:3
X:1
Y:2
i am a rectangle
height:3
width:4
X:1
Y:2
i am a dot
X:1
Y:2
bash-2.05b$ ./TEST
i am a triangle
height:3
width:4
X:1
Y:2
i am a circle
radius:3
X:1
Y:2
i am a rectangle
height:3
width:4
X:1
Y:2
i am a dot
X:1
Y:2
i am a triangle
height:3
width:4
X:1
Y:2
i am a circle
radius:3
X:1
Y:2
i am a rectangle
height:3
width:4
X:1
Y:2
i am a dot
X:1
Y:2
Even advanced C++ isnt too complicated when you understand whats happening.
Any questions / comments / surgestions ?

