440 likes | 839 Views
Chapter 9 Pointers, Virtual Functions and Polymorphism. §9.1 Introduction §9.2 Pointers to Objects §9.3 Virtual Functions §9.4 Dynamic Casting. §9.1 Introduction. Polymorphism: “one name, multiple forms” Functions, data types Function binding Invocation statement function body
E N D
Chapter 9 Pointers, Virtual Functions and Polymorphism §9.1 Introduction §9.2 Pointers to Objects §9.3 Virtual Functions §9.4 Dynamic Casting
§9.1 Introduction • Polymorphism: “one name, multiple forms” • Functions, data types • Function binding • Invocation statement function body • Compile time polymorphism • Static (early) binding, static linking • Function overloading • Operator overloading • Run time polymorphism • Dynamic (late) binding, dynamic linking • Virtual function + pointer of base class
Techniques for Polymorphism Polymorphism Compile time polymorphism Run time polymorphism Function Overloading Operator overloading Virtual function
Example Situation class HM { public: void show(){ cout<<"Human\n"; } }; class CN: public HM { public: void show(){ cout<<“Chinese\n"; } }; class CT: public CN{ public: void show(){ cout<<“Cantonese\n"; } }; int fun(HM h){h.show();} fun(HM()); fun(CN()); fun(CT()); Dynamic binding Human Human Human Human Chinese Cantonese Anonymous object!
§9.2 Pointers to Objects • Create objects at run time class item {}; item x; item *it_ptr = &x; • Referring member functions x.show(); it_ptr->show(); (*it_ptr).show(); • Array of objects item * ptr = new item[10];
The “this” Pointer • A special built-in pointer that points to the current object • Used to cope with hidden data fields // Construct a circle object Circle::Circle(double radius) { this->radius = radius; (*this).radius = radius; } // Set a new radius void Circle::setRadius(double radius) { this->radius = (radius >= 0) ? radius : 0; }
The “this” Pointer Person &Person::greater(Person& x) { if (x.age>age) return x; else return *this; } max = a.greater(b); the argument object! the invoking object!
Pointers to Derived Classes • Pointers of a base class type is compatible with pointers of a derived class • Statements for a base class is workable for derived classes B *cptr;//pointer to class B type variable B b;//base object D d;//derived object cptr = &b;//cptr points to object b cptr->show(); cptr = &d; //cptr points to object d cptr->show();
int main(){ B * bptr; //base pointer B base; //base object bptr = &base; bptr->b = 100; cout<<"bptr …to base…\n“; bptr->show(); D derived; //derived object bptr = &derived; bptr->b=200; cout<<"bptr …to derived…\n“; bptr->show(); D *dptr; dptr= &derived; dptr->d=300; cout<<"dptr is derived type…\n“; dptr->show(); cout<<"using ((D*)bptr)"<<endl; ((D*)bptr)->d=400; ((D*)bptr)->show(); return 0; } class B{ public: int b; void show() {cout<<"b="<<b<<endl;} }; class D : public B{ public: int d; void show(){ cout<<"b="<<b<<endl; cout<<"d="<<d<<endl; } };
§9.3 Virtual Functions • The function declared with the keyword “virtual” • Overriding • To redefine a virtual function in the derived class class B { public: virtual string toString() { return "class B"; } }; class D: public B { string toString() { return "class D"; } };
Example of Virtual Functions int main(){ B b; D d; B *bptr; cout<<“bptr points to Base“; bptr=&b; bptr->display(); bptr->show(); cout<<“bptr points to Derived"; bptr = &d; bptr->display(); bptr->show(); return 0; } class B { public: void display(){ cout<<“Display base";} virtual void show(){ cout<<“\n show base“;} }; class D: public B { public : void display(){ cout<<"Display derived";} void show(){ cout<<“show derived";} };
Notes on Virtual Functions • Realize dynamic binding • Must be accessed by using object pointers/references • Must be defined in base class • Should be redefined (overriding) in the derived class • If not, base version will be invoked • No virtual constructors • Virtual destructors are allowed • Can be a friend of another class
Virtual Destructors class B { public: ~B() { cout<<“Dest B\n”; } }; • class D: public B { • public: • ~D() { • cout<<“Dest D\n”; • } • }; virtual ~B(){ int main() { B *bp = new D(); …… delete bp; …… } Dest D Dest B Dest B
Pure Virtual Functions • A function without body • does nothing, just a placeholder • Also called abstract function • Classes has pure virtual function can’t be used to create objects • Compiler requires each derived class: • define the function, or • continue to declare it as a abstract function virtual void display() = 0;
Abstract Classes • Class is the abstraction of instances/objects • A base class is more abstract/general than derived classes • Abstract class (抽象类) • In logic: • A class so abstract that it cannot have any specific instances • It can only be used as base class • In syntax: • A class with abstract functions (抽象函数)
Abstract Function • I.e. Pure Virtual Function (纯虚函数) • Can’t be implemented in abstract classes • For example class GeometricObject{ protected: GeometricObject(); GeometricObject(string color, bool filled); public: string getColor(); void setColor(string color); bool isFilled(); void setFilled(bool filled); string toString(); virtual double getArea() = 0; virtual double getPerimeter() = 0; private: string color; bool filled; };
Abstract Class Example AbstractGeometricObject.h AbstractGeometricObject.cpp DerivedCircle2.h DerivedCircle2.cpp Rectangle2.h Rectangle2.cpp TestGeometricObject2 .cpp Run
§9.4 Dynamic Casting • How to display radius, diameter, area, and perimeter if the object is a circle? // A function for displaying a geometric object void displayGeometricObject(GeometricObject &object) { cout << "The area is " << object.getArea() << endl; cout << "The perimeter is " << object.getPerimeter() << endl; }
Dynamic Casting • The dynamic_cast operator checks if p points to a Circle object • If yes, p1 is assigned the address of the object • If no, p1 is assigned to NULL (the constant 0) GeometricObject *p = &object; Circle *p1 = dynamic_cast<Circle*>(p); if (p1 != NULL) { cout << "The radius is " << p1->getRadius() << endl; cout << "The diameter is " << p1->getDiameter() << endl; } Run DynamicCastingDemo
Upcasting and Downcasting • Upcasting • Assigning a pointer of a derived class type to a pointer of its base class type • Done implicitly • Downcasting • Assigning a pointer of a base class type to a pointer of its derived class type • Done explicitly using dynamic_cast GeometricObject *p = new Circle(1); Circle *p1 = new Circle(2); p = p1; p1 = dynamic_cast<Circle*>(p);
The typeid Operator • To return the type information of a variable/object • The information is stored in an object of class type_info • For example, string x; cout << typeid(x).name() << endl;
Summary • Polymorphism • Compile / Runtime polymorphism • Object pointers • this pointer • Techniques to realize runtime polymorphism • Virtual function • Invoked via pointer of base class • Abstract function
Review Questions • Q9.2 • Q9.4 • Q9.8