360 likes | 619 Views
Inheritance. Behold the Power!. Where are we. Learned the basics of classes Classes so far just provide a convenient container Definitely useful but not the end of the story. What OO really brings to the table. Inheritance. Polymorphism. Inheritance vs. Polymorphism. Inheritance.
E N D
Where are we • Learned the basics of classes • Classes so far just provide a convenient container • Definitely useful but not the end of the story
What OO really brings to the table Inheritance Polymorphism
Inheritance vs. Polymorphism Inheritance Polymorphism • Design-time feature • Describes what is possible • Constrains the run-time • Run-time feature • Doesn’t need inheritance to work • Can be more dynamic • Gets weird … but very cool
Inheritance • Establishes a hierarchical relationship • Use to abstract out or capture strong commonality among classes • Typically thought of an an “is a” relationship
Example Vehicle Boat “is a” Vehicle Boat Car Car “is a” Vehicle
Notation and Syntax “base class” “super class” “parent” class Vehicle { // Whatever makes up a vehicle }; Vehicle class Boat : public Vehicle { // Whatever makes up a boat }; Boat “sub class” “child”
Inheritance • Like genetics, one thing inherits characteristics of another • Class inheritance: • Everything but the constructors and deconstructor
Conceptual Object Implications Vehicle Vehicle v; v Boat Boat b; v b Conceptually, part of the make up of an instance of B is an instance of V
Example class Vehicle { private: string vin; public: void setVIN(string newVIN) { vin = initVIN; } string getVIN() { return vin; } }; class Boat : public Vehicle { public: // Perhaps other interesting // boat ops }; Notice that we can invoke setVIN() and getVIN() even though they are not declared explicitly in the class Boat Boat b; b.setVIN(“a1b2c3”); cout << b.getVIN();
Heirarchies Vehicle AquaticVehicle LandVehicle Submarine Boat Car Tank
Visibility class Boat : public Vehicle { public: // Perhaps other interesting // boat ops }; • Notice that we declared the base class as public • We have control over the visibility of the base class members • Base classes can be declared public, protected or private • Default is private • Need to understand how this effects the visibility of the base class members
Members in the base class are limited by the visibility declaration of the subclass Public is the most common Visibility • Rule of thumb • Base class member visibility is capped by the declaration • Only affects members whose visibility is greater
Visibility • Boils down to two things • What can the outside world see? • Only public members • What can the subclass see? • Only public and protected members
External Visibility class B : public A { public: void b_pub() { a_pub(); //OK a_pro(); //OK a_pri(); //NO }; B b; b.a_pub(); //OK b.a_pro(); //NO b.a_pri(); //NO class A { private: void a_pri(); protected: void a_pro(); public: void a_pub(); }; class B : protected A { public: void b_pub() { a_pub(); //OK a_pro(); //OK a_pri(); //NO }; B b; b.a_pub(); //NO b.a_pro(); //NO b.a_pri(); //NO class B : private A { public: void b_pub() { a_pub(); //OK a_pro(); //OK a_pri(); //NO };
Hierarchy and Visibility class B : public A { public: void b_pub() { a_pub(); //OK a_pro(); //OK a_pri(); //NO }; class C : public B { public: void c_pub() { a_pub(); //OK a_pro(); //OK a_pri(); //NO }; class A { private: void a_pri(); protected: void a_pro(); public: void a_pub(); }; class B : protected A { public: void b_pub() { a_pub(); //OK a_pro(); //OK a_pri(); //NO }; class C : public B { public: void c_pub() { a_pub(); //OK a_pro(); //OK a_pri(); //NO }; class B : private A { public: void b_pub() { a_pub(); //OK a_pro(); //OK a_pri(); //NO }; class C : public B { public: void c_pub() { a_pub(); //NO a_pro(); //NO a_pri(); //NO };
Using Private Data class Vehicle { private: string vin; public: void setVIN(string newVIN) { vin = initVIN; } string getVIN() { return vin; } }; class Boat : public Vehicle { private: string color; string make; string model; public: string toString() { return “The boat is a “ + color + “ “ + make + “ “ + model + “ with VIN: “ + getVIN(); } }; In order to access the VIN number, the Boat class has to invoke the getVIN() operaton.
Using Protected Data class Vehicle { protected: string vin; public: void setVIN(string newVIN) { vin = initVIN; } string getVIN() { return vin; } }; class Boat : public Vehicle { private: string color; string make; string model; public: string toString() { return “The boat is a “ + color + “ “ + make + “ “ + model + “ with VIN: “ + vin; } }; By declaring vin to be protected, the base class has access to it.
Private vs. Protected • Significant design trade off • Private data means more complicated interfaces • Protected data increases possibility for error • Happy medium • Declare data private and provide descendents access via protected operations
Constructors • Constructors are not inherited • If no default constructor exists on a base class, the subclass must explicitly invoke
Example class Vehicle { private: string vin; public: Vehicle() { vin = “UNKNOWN”;} void setVIN(string newVIN) { vin = initVIN; } string getVIN() { return vin; } }; The Boat contructor implicitly calls the Vehicle default contructor. class Boat : public Vehicle { public: public Boat(string initVIN) { setVIN(initVIN); } };
Example : Error!!! class Vehicle { private: string vin; public: Vehicle(string initVIN) { vin = initVIN; } string getVIN() { return vin; } }; • This would cause a compiler error • The Boat constructor wants to invoke the default constructor which is hidden class Boat : public Vehicle { public: public Boat(string initVIN) { setVIN(initVIN); } };
Example : Correction class Vehicle { private: string vin; public: Vehicle() { vin = “UNKNOWN”;} Vehicle(string initVIN) { vin = initVIN; } string getVIN() { return vin; } }; • This would work since a default constructor is defined • If our intention was to not let vehicles exist without an explicit VIN, this would not be a correct design class Boat : public Vehicle { public: public Boat(string initVIN) { setVIN(initVIN); } };
Example : Better Way class Vehicle { private: string vin; public: Vehicle(string initVIN) { vin = initVIN; } string getVIN() { return vin; } }; Here, the Boat constructor explicitly invokes the Vehicle constructor class Boat : public Vehicle { public: public Boat(string initVIN) : Vehicle(initVIN){ } };
Order of Constructors Vehicle • Base class constructors are invoked before the subclass constructors • Makes sense, right? • Creating an instance of Submarine would cause • Vehicle() to fire • AquaticVehicle() to fire • Submarine() to fire Vehicle() AquaticVehicle AquaticVehicle() Submarine Submarine()
Deconstructors • The game is simple here • There is only one deconstructor and you can never invoke it • When subclassing, deconstructors are fired in the reverse order of constructors • Makes sense, right?
Ok… What’s the big deal? • So far we’ve used inheritance as a convenience • Build up one entity based on another • What if we don’t like a particular behavior • We can override it
Example : Overriding class Rectangle { private: double length; dobule width; public: void setLength(double newLength) { length = newLength; } void setWidth(double newWidth) { width = newWidth; } double getArea() { return length*width; } }; The Square class needs a different behavior. It redefines the methods appropriately. class Square : public Rectangle { public: void setLength(double newLength) { Rectangle::setLength(newLength): Rectangle::setWidth(newLength): } void setWidth(double newWidth) { Rectangle::setLength(newWidth): Rectangle::setWidth(newWidth): } };
Example : Overriding What’s the output? Rectangle r; Square s; r.setLength(5); r.setLength(10); cout << r.getArea(); s.setLength(5); s.setLength(10); cout << r.getArea();
What is displayed? class Vehicle { private: string vin; public: void setVIN(string newVIN); string getVIN(); string toString() { return “This vehicle has VIN: “ + vin; } }; Boat b(“red”, “AquaFord”, “AquaFocus”); Vehicle v; b.setVIN(“12345”); v = b; v.setVIN(“54321”); cout << v.toString() << endl << endl; cout << b.toString() << endl << endl; class Boat : public Vehicle { private: string color; string make; string model; public: Boat(string initColor, string initMake, string initModel); string toString() { return “The boat is a “ + color + “ “ + make + “ “ + model + “ with VIN: “ + getVIN(); } };
What is displayed? class Vehicle { private: string vin; public: void setVIN(string newVIN); string getVIN(); string toString() { return “This vehicle has VIN: “ + vin; } }; Boat b(“red”, “AquaFord”, “AquaFocus”); Vehicle v; b.setVIN(“12345”); v = b; v.setVIN(“54321”); cout << v.toString() << endl << endl; cout << b.toString() << endl << endl; class Boat : public Vehicle { private: string color; string make; string model; public: Boat(string initColor, string initMake, string initModel); string toString() { return “The boat is a “ + color + “ “ + make + “ “ + model + “ with VIN: “ + getVIN(); } }; c:> > myProg.exe This vehicle as VIN: 54321 The boat is a red AquaFord AquaFocus with VIN: 12345
Visualization Boat b(“red”, “AquaFord”, “AquaFocus”); Vehicle v; v = b; Copy the “vehicle-ness” of b to v (vehiclicity?) vehicle stuff v vehicle b Boat stuff
What about this? Boat b(“red”, “AquaFord”, “AquaFocus”); Vehicle v; b = v; // <-- This changed.
What is displayed? class Vehicle { private: string vin; public: void setVIN(string newVIN); string getVIN(); string toString() { return “This vehicle has VIN: “ + vin; } }; Boat *b = new Boat(“red”, “AquaFord”, “AquaFocus”); Vehicle *v; B->setVIN(“12345”); v = b; v->setVIN(“54321”); cout << v->toString() << endl << endl; cout << b->toString() << endl << endl; class Boat : public Vehicle { private: string color; string make; string model; public: Boat(string initColor, string initMake, string initModel); string toString() { return “The boat is a “ + color + “ “ + make + “ “ + model + “ with VIN: “ + getVIN(); } };
What is displayed? class Vehicle { private: string vin; public: void setVIN(string newVIN); string getVIN(); string toString() { return “This vehicle has VIN: “ + vin; } }; Boat *b = new Boat(“red”, “AquaFord”, “AquaFocus”); Vehicle *v; B->setVIN(“12345”); v = b; v->setVIN(“54321”); cout << v->toString() << endl << endl; cout << b->toString() << endl << endl; class Boat : public Vehicle { private: string color; string make; string model; public: Boat(string initColor, string initMake, string initModel); string toString() { return “The boat is a “ + color + “ “ + make + “ “ + model + “ with VIN: “ + getVIN(); } }; c:> > myProg.exe This vehicle as VIN: 54321 The boat is a red AquaFord AquaFocus with VIN: 54321