Abstract base classes are something very similar to our CPolygon class of our previous example. The only difference is that in our previous example we have defined a valid area() function with a minimal functionality for objects that were of class CPolygon (like the object poly), whereas in an abstract base classes we could leave that area() member function without implementation at all. This is done by appending =0 (equal to zero) to the function declaration.
An abstract base CPolygon class could look like this:
1
2
3
4
5
6
7
8
9
|
// abstract class CPolygon
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area () =0;
};
|
Notice how we appended
=0 to
virtual int area () instead of specifying an implementation for the function. This type of function is called a
pure virtual function, and all classes that contain at least one pure virtual function are
abstract base classes.
The main difference between an abstract base class and a regular
polymorphic class is that because in abstract base classes at least one
of its members lacks implementation we cannot create instances (objects)
of it.
But a class that cannot instantiate objects is not totally useless. We
can create pointers to it and take advantage of all its polymorphic
abilities. Therefore a declaration like:
would not be valid for the abstract base class we have just declared,
because tries to instantiate an object. Nevertheless, the following
pointers:
1
2
|
CPolygon * ppoly1;
CPolygon * ppoly2;
|
would be perfectly valid.
This is so for as long as
CPolygon includes a pure virtual
function and therefore it's an abstract base class. However, pointers to
this abstract base class can be used to point to objects of derived
classes.
Here you have the complete example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
// abstract base class
#include <iostream>
using namespace std;
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area (void) =0;
};
class CRectangle: public CPolygon {
public:
int area (void)
{ return (width * height); }
};
class CTriangle: public CPolygon {
public:
int area (void)
{ return (width * height / 2); }
};
int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout << ppoly1->area() << endl;
cout << ppoly2->area() << endl;
return 0;
}
|
20
10
|
If you review the program you will notice that we refer to objects of
different but related classes using a unique type of pointer (
CPolygon*). This can be tremendously useful. For example, now we can create a function member of the abstract base class
CPolygon that is able to print on screen the result of the
area() function even though
CPolygon itself has no implementation for this function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
// pure virtual members can be called
// from the abstract base class
#include <iostream>
using namespace std;
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area (void) =0;
void printarea (void)
{ cout << this->area() << endl; }
};
class CRectangle: public CPolygon {
public:
int area (void)
{ return (width * height); }
};
class CTriangle: public CPolygon {
public:
int area (void)
{ return (width * height / 2); }
};
int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly1->printarea();
ppoly2->printarea();
return 0;
}
|
20
10
|
Virtual members and abstract classes grant C++ the polymorphic
characteristics that make object-oriented programming such a useful
instrument in big projects. Of course, we have seen very simple uses of
these features, but these features can be applied to arrays of objects
or dynamically allocated objects.
Let's end with the same example again, but this time with objects that are dynamically allocated:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
// dynamic allocation and polymorphism
#include <iostream>
using namespace std;
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area (void) =0;
void printarea (void)
{ cout << this->area() << endl; }
};
class CRectangle: public CPolygon {
public:
int area (void)
{ return (width * height); }
};
class CTriangle: public CPolygon {
public:
int area (void)
{ return (width * height / 2); }
};
int main () {
CPolygon * ppoly1 = new CRectangle;
CPolygon * ppoly2 = new CTriangle;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly1->printarea();
ppoly2->printarea();
delete ppoly1;
delete ppoly2;
return 0;
}
|
20
10
|
Notice that the
ppoly pointers:
1
2
|
CPolygon * ppoly1 = new CRectangle;
CPolygon * ppoly2 = new CTriangle;
|
No comments:
Post a Comment