C How to Program, 6/e 1992-2010 by Pearson Education, Inc. All Rights Reserved. 1
Standard Behavior: When the compiler is working out which member function to call, it selects according to the type of the pointer not to the type of the object it points However, in polymorphism type of the object the pointer points is used. 2
Inheritance Hierarchy Classes in Hierarchy Must Have Virtual Methods There Must Be a Pointer to the Base Class 3
One way to determine the type of an object is to use a switch statement to check the value of a field in the object. This allows us to distinguish among object types, then invoke an appropriate action for a particular object. Using switch logic exposes programs to a variety of potential problems. For example, you might forget to include a type test when one is warranted, or might forget to test all possible cases in a switch statement. When modifying a switch-based system by adding new types, you might forget to insert the new cases in all relevant switch statements. Every addition or deletion of a class requires the modification of every switch statement in the system; tracking these statements down can be time consuming and error prone. 1992-2010 by Pearson Education, Inc. All Rights Reserved. 4
EXAMPLE: class Vehicle { public: int vehicletype; class Car : public Vehicle { public: Car() {vehicletype = 1;} class Truck : public Vehicle { public: Truck() {vehicletype = 2;} main() { Vehicle *v[2]; v[0] = new Car(); v[1] = new Truck(); for (int i = 0; i < 2; i++) switch(v[i]->vehicletype) { case 1: cout << "30 mpg" << endl; break; case 2: cout << "10 mpg" << endl; break; } } 5
6
There are cases in which it s useful to define classes from which you never intend to instantiate any objects. Such classes are called abstract classes. Because these classes normally are used as base classes in inheritance hierarchies, we refer to them as abstract base classes. These classes cannot be used to instantiate objects, because, as we ll soon see, abstract classes are incomplete derived classes must define the missing pieces. An abstract class provides a base class from which other classes can inherit. 1992-2010 by Pearson Education, Inc. All Rights Reserved. 7
Abstract base classes are too generic to define real objects; we need to be more specific before we can think of instantiating objects. For example, if someone tells you to draw the twodimensional shape, what shape would you draw? Classes that can be used to instantiate objects are called concrete classes. Such classes define every member function they declare. Concrete classes provide the specifics that make it reasonable to instantiate objects. 1992-2010 by Pearson Education, Inc. All Rights Reserved. 8
A class is made abstract by declaring one or more of its virtual functions to be pure. A pure virtual function is specified by placing = 0 in its declaration, as in // pure virtual function virtual void draw() = 0; The = 0 is a pure specifier. Pure virtual functions do not provide implementations. A class containing a pure virtual function is called ABSTRACT CLASS 1992-2010 by Pearson Education, Inc. All Rights Reserved. 9
We cannot instantiate objects of an abstract base class. We can use the abstract base class to declare pointers and references that can refer to objects of any concrete classes derived from the abstract class. Programs typically use such pointers and references to manipulate derived class objects polymorphically. 1992-2010 by Pearson Education, Inc. All Rights Reserved. 10
Some classes such as class Shape represent abstract concepts for which the objects cannot exist. A shape class makes sense only as the base class of some derived from it class Shape { public: virtual void area() = 0; } Shape Rectangle Circle Triangle 12
class Shape { public : virtual double area() = 0; class Circle: public Shape { private: int r; public: double area() { return 3.14*r*r; } Circle(int r) { this->r = r; } class Rectangle: public Shape { private: int h; int w; public: double area() { return h* w; } Rectangle(int h, int w) { this->h = h; this->w = w;} 13
class Shape {... class Circle: public Shape {... class Rectangle: public Shape {... void main() { Rectangle rect(3,2); Circle circ(2); cout << rect.area() << endl; cout << circ.area() << endl; Shape x3;!!!! ERROR // Cannot Create an Object from an Abstract Class } Shape *p1, *p2; // OK! Can Declare Pointers p1 = new Rectangle (1, 1) ; p2 = new Circle(1) ; cout << p2->area() << endl; cout << p1->area() << endl; 14
Has implementation? Virtual Function void foo(int x) {...} Yes Pure Virtual Function void foo(int x)=0; No Derived class May override Must override Class is Concrete Abstract Pure virtual functions are used when it does not make sense for the base class to have an implementation of a function, but you want all concrete derived classes to implement the function. 1992-2010 by Pearson Education, Inc. All Rights Reserved. 15
class Employee { public : Employee(string n); virtual float income() = 0; // Pure virtual string name(); protected: string empname; Employee class can not be instantiated because it is abstract. It has a pure virtual function. 17
class Company { public : Company(int count); void print_all_incomes(); void add_employee(employee* employee); protected : Employee *employees[1000]; // HAS-A Relationship int nb_employees; Company Employee Manager Clerk Engineer 18
class Employee { public : Employee(string n) {empname = n;} virtual float income() = 0; string name() {return empname; protected: string empname; class Manager : public Employee { public : Boss(string n) : Employee(n) {} float income() {return 100000; class Clerk: public Employee { public: Clerk(string n) : Employee(n) {} float income() {return 50000;} 19
class Company { public : Company(int count) { nb_employees = count;} void print_all_incomes(); void add_employee( Employee* employee ); protected : Employee *employees[1000]; int nb_employees; void Company::print_all_incomes() { for( int i = 0; i < nb_employees; ++i ) { cout << employees[i]->name() << ": " << employees[i]->income() << endl; } } void Company::add_employee(Employee *e) { employees[nb_employees++] = e; } 20
int main() { Company company(0); Employee *billgates = new Manager( "Bill" ); company.add_employee( billgates ); Employee *john = new Clerk( "John" ); company.add_employee( john ); Employee *mary = new Engineer( "Mary" ); company.add_employee( mary ); } company.print_all_incomes(); return 0; 21
Runtime type information (RTTI) and dynamic casting, which enable a program to determine the type of an object at execution time and act on that object accordingly. 1992-2010 by Pearson Education, Inc. All Rights Reserved. 22
Since we process the shapes polymorphically, we cannot (with the techniques we ve learned) be certain as to which type of Shape is being manipulated at any given time. Circle shape must be identified when we encounter them so that we can paint it with blue. To accomplish this, we use operator dynamic_cast to determine whether the type of each object is Circle. Dynamically downcast Shape pointer from type Shape * to type Circle *. If the value returned by the dynamic_cast operator is not 0 (NULL), the object is the correct type 1992-2010 by Pearson Education, Inc. All Rights Reserved. 23
Operator typeid returns a reference to an object of class type_info that contains the information about the type of its operand, including the name of that type. When invoked, type_info member function name returns a pointer-based string that contains the type name (e.g., "class Circle") of the argument passed to typeid. To use typeid, the program must include header file <typeinfo>. 1992-2010 by Pearson Education, Inc. All Rights Reserved. 24
class Shape { public: virtual void draw() { cout << "hi from class Shape" << endl;} class Rectangle : public Shape { public: void draw() { cout << "hi from class Rectangle" << endl;} void Rectonly() { cout << "\tproof I am of type Rectangle" << endl;} class Prizm : public Rectangle { public: void draw() { cout << "hi from class Prizm" << endl;} void Prizmonly() { cout << "\tproof I am of tpye Prizm" << endl;} 25
dynamic_cast, typeid and type_info Example 2/2 int main() { // Make classes of type Shape Shape* a = new Shape(); // a is of Type Shape and points to a copy of Shape Shape* b = new Rectangle(); // b is of Type Shape and points to a copy of Rectangle Shape* c = new Prizm(); // c is of Type Shape and points to a copy of Prizm // Downcasting Rectangle *b2 = dynamic_cast<rectangle *>(b); // downcast b from // type Shape to type Rectangle Prizm *c2 = dynamic_cast<prizm *>(c);// cast c into c2 - Type Shape to Prizm cout << Type = << typeid(*b).name() << endl;; // in case you don't believe me uncomment these for proof // b->rectonly(); // c->prizmonly(); } a->draw(); b2->draw(); c2->draw(); b2->rectonly(); c2->prizmonly(); 26
A LINK LIST IMPLEMENTATION USING C++ CLASSES int number A pointer to the next Node NODE CLASS number next number next number next NULL head head->next 27
class Node { private: int number; Node * next; public : Node() { number = 0; next=null; } int getnumber() { return number; } void setnumber(int n) { number=n; } Node * getnext() { return this->next;} void addnode(node * x) { Node * p; for (p = this; p->next!=null; p=p->next); p->next=x; } 28
main() { Node * head = new Node(); int y; cin >> y; head->setnumber(y); Node * q; for (int i=1; i<5; i++) { cin >> y; q = new Node(); q->setnumber(y); head->addnode(q); } for( q = head; q!= NULL; q=q->getnext() ) cout<< q->getnumber(); } 29