370 likes | 513 Views
COM 262 Object Development. Inheritance II. Class hierarchy. Relationship?. class: Order – to contain list’ of shapes. Class relationships. Aggregation. Inheritance. Inheritance. Aggregation. Rectangle rect_list[10]. Circle cir_list[10]. ‘Lists’ of shapes.
E N D
COM 262Object Development Inheritance II
Relationship? class: Order – to contain list’ of shapes
Class relationships Aggregation Inheritance Inheritance Aggregation
Rectangle rect_list[10] Circle cir_list[10] ‘Lists’ of shapes • How to store the lists of rectangle and circle aluminum sheet objects? • Two lists?
Rectangle Circle class: Order • contains list of rectangles and list of circles class Order{ private: float total_cost; float total_surface_area; Rectangle rect_list[10]; Circle cir_list[10]; int recNos, cirNos; public: Order ( ) ; // constructor void addItem(); void displayOrder() float compute_tot_cost(); float compute_tot_area(); } ;
Rectangle rect_list[num] Circle cir_list[num] To calculate total surface area for ( int i=0; i < num; i++) rec_area += rect_list[i].compute_area( ); for ( int i=0; i < num; i++) cir_area += cir_list[i].compute_area( );
shapes is heterogeneous list polymorphic array via One list for all.. To find total surface area of order: for ( int i=0; i < num; i++) sur_area += shapes[i].compute_area( ); shapes
Polymorphism • An essential requirement of polymorphism is the ability to refer to objects without regards to their classes and hence one should be able to send messages without knowing the class of the recipient objects • Via virtual functions
shapes Data member mismatch • Rectangles and Circles have different amounts of data members.. • Cannot use ordinary variables as elements of the arrays
Memory Memory Pointers and References * Pointers contain memory addresses & References are aliases Pointer Variable name/ Alias(es)
Allowed: parent1 = child1; Pointers and References class Parent{ protected: float per_unit_cost; public: // ....... } ; // end class class Child : public Parent { private: float length; float breadth; public: //...... } ; //end class Parent parent1, parent1; //instantiating Child child1, child2; // parent & child Objects leads to loss of data Use pointers instead.. Addresses are the same size.
allowed par_ptr = &child1; allowed par_ptr = &parent1; Pointer to Parent object Parent * par_ptr;//pointer to Parent object No loss of data: par_ptr refers to the complete child object.
New facts • An object, pointer or reference will be implicitly converted from a derived class to a public base class.
shapes Array of pointers to parent class Shape * shapes[max_no];
shapes pointer to a Rectangle object pointer to a Circle object pointer to a Rectangle object pointer to a Rectangle object pointer to a Circle object pointer to a Rectangle object Shape *shapes[MAX_NO]; Circle *cir_ptr; Rectangle *rect_ptr; Array of pointers to parent class
Since shapes contains pointers Dynamic Memory // get details of the new Circle/Rectangle object // create a new object DYNAMICALLY ..... // assign object pointer to the polymorphic array ... // compute total surface area ... Using the 'new' operator for n shapes sur_area += shapes[n] compute_area( );
Revised implementation of Order Class class Order{ private: float total_cost; float total_surface_area; // Rectangle rect_list[10]; // Circle cir_list[10]; // int recNos, cirNos; Shape *shapes[20]; int noOfItemes; public: Order ( ) ; // constructor // FUNCTIONS } ;
Revised implementation of Order Class class Order{ private: float total_cost; float total_surface_area; // Rectangle rect_list[10]; // Circle cir_list[10]; // int recNos, cirNos; Shape *shapes[20]; int noOfItemes; public: Order ( ) ; // constructor // FUNCTIONS } ; Shape
Class relationships Aggregation Inheritance Inheritance
via virtual functions Virtual Functions • But how does the compiler know which functions to use for n shapes sur_area += shapes[n] compute_area( ); • Shape ::compute_area( ) • Circle::compute_area( ) • Rectangle::compute_area( )
Virtual Functions class Shape{ protected: float per_unit_cost; int quantity; public: // constructor Shape(float c) {per_unit_cost = c;} virtual float compute_area(void) {return 0.0} // non virtual function float cost(void) {return compute_area( ) *per_unit_cost;} } ; class Circle: public Shape { private: float radius; public: // constructor circle (float rad, float cost) : Shape(cost) { radius = rad; } // member function float compute_area (void) { return pi*rad*rad; } } ;
New facts • To allow for the polymorphic behaviour in the example, C++ allows late-binding (dynamic binding) of functions as opposed to the conventional early-binding (static binding) • Virtual functions and pointers facilitate late-binding (dynamic binding) of functions in C++. • The reserved word virtual is used only in the base class. • Functions that override a virtual function is always virtual and do not have to be explicitly declared as such.
Virtual functions versus non-virtual class Parent { protected: int j, k; public: virtual voidvf( ) { cout <<“vf:parent\n”; } voidnvf ( ) { cout<<“nvf:parent\n”; } }; class Child:public Parent{ protected: int m, n; public: void vf( ) { cout <<“vf:child\n”; } void nvf ( ) { cout<<“nvf:child\n”; } };
Virtual functions versus non-virtual Output: Parent parent1; Child child1; parent1.vf( ); parent1.nvf( ); child1.vf( ); child1.nvf( ); vf : parent nvf : parent vf : child nvf : child
Virtual functions versus non-virtual • For non-virtual functions, the declaration of the pointer variable determines which function will be used. • For virtual functions, the class of the object pointed to determines which function definition will be used Parent parent1; Parent * ptr_parent; Child child1; ptr_parent = & parent1; ptr_parent vf( ); ptr_parent nvf( ); ptr_parent = & child1; ptr_parent vf( ); ptr_parent nvf( ); Output: vf : parent nvf : parent vf : child nvf : parent
list reference to child object reference to parent object reference to child object reference to child object Virtual functions versus non-virtual Output: Parent *list[4]; for (int i = 0; i < 4; i++) list[i] vf( ); vf : child vf : parent vf : child vf : parent
list reference to child object reference to parent object reference to child object reference to child object Virtual functions versus non-virtual Output: Parent *list[4]; for (int i = 0; i < 4; i++) list[i] nvf( ); nvf : parent nvf : parent nvf : parent nvf : parent
Compiler choice • But how does the above example knows which functions to use ? • Shape ::compute_area( ) • Circle::compute_area( ) • Rectangle::compute_area( ) for (int i = 0; i < noOfItems; i++) sur_area += shapes[i] compute_area( );
call to: compute_area( ) Shape::compute_area( ) Rectangle::compute_area( ) compute_area( ) VMT Shape::compute_area( ) Rectangle:: compute_area( ) Circle:: compute_area( ) Circle::compute_area( ) Virtual Method Table
New facts • A virtual method table is created for functions that are declared as virtual. • Which actual function is called depends on which class of object made the call.
Summary • Polymorphism via Virtual Functions • Polymorphic arrays (heterogeneous list) • Pointers & References • Dynamic object creation using new operator • Dynamic (late) binding of functions via VMT
Example 1 class Mammal { public: Mammal():itsAge(1) {} virtual ~Mammal() {} void Move() const { cout << "Mammal move one step\n"; } virtual void Speak() const { cout << "Mammal speak!\n"; } protected: int itsAge; }; class Dog : public Mammal { public: Dog() {} virtual ~Dog() {} void Move()const { cout << "Dog moves 5 steps...\n"; } void Speak()const { cout << "Woof!\n"; } void WagTail() { cout << "Wagging Tail...\n"; } };
Example 1 int main() { Mammal *pDog = new Dog; // Mammal pointer pDog Move(); // invoke Mammal::Move() pDog Speak(); // invoke Dog::Speak() !! return 0; }
Example 2 class Mammal { public: Mammal():itsAge(1) { } virtual ~Mammal() { } virtual void Speak() const { cout << "Mammal speak!\n"; } protected: int itsAge; };
Example 2 class Dog : public Mammal { public: void Speak()const { cout << "Woof!\n"; } }; class Cat : public Mammal { public: void Speak()const { cout << "Meow!\n"; } }; class Horse : public Mammal { public: void Speak()const { cout << "Winnie!\n"; } }; class Pig : public Mammal { public: void Speak()const { cout << "Oink!\n"; } };
Example 2 int main() { Mammal* theArray[5]; theArray[0] = new Dog; theArray[1] = new Cat; theArray[2] = new Horse; theArray[3] = new Pig; theArray[4] = new Mammal; for (int i=0;i<5;i++) theArray[i]Speak(); return 0; }