Inheritance and polymorphism, Schemes and Mind Maps of Object Oriented Analysis and Design

Single inheritance is where one class is derived from another class. Objects are defined as extensions previously defined objects. The extension inherits all ...

Typology: Schemes and Mind Maps

2022/2023

Uploaded on 02/28/2023

ekachakra
ekachakra 🇺🇸

4.6

(33)

268 documents

1 / 4

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Page 1 of 4
Inheritanceandpolymorphism
ProfessorsClarkF.OlsonandCarolZander
Inheritancebasics
We’veseentemplatesasonemethodforcodereuse.Anotherimportanttechniqueisinheritance.Oneoftheimportant
benefitsofinheritanceisthatitallowsustoextendaclasswithoutmodifying(orbreaking)theoriginalclass.
Singleinheritanceiswhereoneclassisderivedfromanotherclass.Objectsaredefinedasextensionspreviouslydefined
objects.Theextensioninheritsalldatamembersandmemberfunctions.
Abstractly,inheritancerepresentsanisarelationship.Arectangleisashape.Asquareisarectangle.Wecanbuild
hierarchiesusingthisconcept.Forshapes(thearrowrepresentsanisarelationship):
Thesquareisanexampleofmultipleinheritance.(Thestructureisnotnecessarilyatree.)Notethatwedrawthearrow
fromthe“childclass”orderivedclasstothe“parentclass”orbaseclass.Otherterminologyissuperclassandsubclass.
Everymemberofthederivedclassisalsoamemberofthebaseclass,butnotviceversa.Attributes(likeprivatedata)that
everyshapehasareinheritedbyallthedescendentclasses.Thisdoesn’tmeanthattheyeachhavethesamevalue,but
thattheyhavesomevaluefortheseattributes.Forourgeneralshapes,theremightnotbeanyattributesthatallofthe
derivedclassesshare.Membersofthederivedclassescanhaveadditionalattributes.Quadrilateralshaveacenterof
mass,anarea,andacircumference.
OthercommonlyseenfirstexamplesshowMammalastheparentclasswithchildclassessuchasHuman,Dog,etc.
HereisasimpleexampleofinheritanceinC++.Wecanfirstdefinethebaseclass,whichwillbePerson.
class Person {
public:
string getName() const;
int getAge() const;
bool getGender() const;
void display() const;
private:
string name;
bool gender;
int birthdate; // Could be days elapsed since Jan. 1, 1800.
};
Sha
p
e
Quadrilateral
Parallelogram
Trapezoid
Circle
Square Rectangle Rhombus
Conic section
Square
Concave
quadrilateral Parabola Ellipse Hyperbola
pf3
pf4

Partial preview of the text

Download Inheritance and polymorphism and more Schemes and Mind Maps Object Oriented Analysis and Design in PDF only on Docsity!

Inheritance and polymorphism

Professors Clark F. Olson and Carol Zander

Inheritance basics

We’ve seen templates as one method for code reuse. Another important technique is inheritance. One of the important benefits of inheritance is that it allows us to extend a class without modifying (or breaking) the original class. Single inheritance is where one class is derived from another class. Objects are defined as extensions previously defined objects. The extension inherits all data members and member functions.

Abstractly, inheritance represents an is‐a relationship. A rectangle is a shape. A square is a rectangle. We can build hierarchies using this concept. For shapes (the arrow represents an is‐a relationship):

The square is an example of multiple inheritance. (The structure is not necessarily a tree.) Note that we draw the arrow from the “child class” or derived class to the “parent class” or base class. Other terminology is superclass and subclass. Every member of the derived class is also a member of the base class, but not vice versa. Attributes (like private data) that every shape has are inherited by all the descendent classes. This doesn’t mean that they each have the same value, but

that they have some value for these attributes. For our general shapes, there might not be any attributes that all of the derived classes share. Members of the derived classes can have additional attributes. Quadrilaterals have a center of mass, an area, and a circumference.

Other commonly seen first examples show Mammal as the parent class with child classes such as Human, Dog, etc. Here is a simple example of inheritance in C++. We can first define the base class, which will be Person.

class Person { public: string getName() const; int getAge() const; bool getGender() const; void display() const; private: string name; bool gender; int birthdate; // Could be days elapsed since Jan. 1, 1800. };

Shape

Quadrilateral

Parallelogram

Trapezoid

Circle

RectangleSquare Rhombus

Conic section

Square

Concave quadrilateral

Parabola (^) Ellipse Hyperbola

Now we can define derived classes that inherit from Person. For example, every student is a person, so inheriting the

attributes (members) from the Person class is reasonable.

class Student : public Person { float getGPA() const; void display() const; private: float gpa; };

The “public Person” after the class name indicates that the Student class inherits from the Person class in “public” way. All public operations in the Person class remain public in the Student class. We could instead use private inheritance in which the public members of Person become private in Student. This is unusual, but there are cases where you don’t want people to be able to use the interface to the base class. The default is private inheritance, so it is important to remember the “public.”

In the Student class, we have added members that can be used for a student and overridden the display operation. (You

override an operation if the signature is the same and overload it if the signature is different.) If the display operation is used for an object known to be a Student, then the Student’s display is used instead of the Person’s display. Can it be the case that we don’t know whether an object is a student or not? Consider the following code: Person *p; if (someBool) p = new Person; else p = new Student; p->display(); This is legal code, using a concept called polymorphism. Which display routine is used? In this case, it is the Person’s display routine, even if p is a Student. However, there are ways to change this. We’ll return to this concept in some detail

later. Note that the following is illegal code. Student *p = new Person; // ILLEGAL A Student is a Person, but a Person is not necessarily a Student.

We can use “partial overriding” by calling the base class method in the derived class method. void Student::display() const { Person::display(); cout << “ “ << gpa; }

Note that data that is private in the base class, cannot be accessed by the derived class. Of course, sometimes we would like to be able to access this data. There are two ways to do this. The first (and safest) way is to use accessor or mutators in the base class. The second is to change the visibility of the data. However, we certainly don’t want to change the visibility

to “public.” There is another visibility that allows derived classes to access the data, but not other classes. This visibility is “protected.” So, if we want the Student class to be able to access the birthdate attribute (but not the others), use:

protected: int birthdate; private: string name; bool gender;

Note that the default constructor for Student will call the constructor for Person and then perform the default initialization on new data members, such as gpa. If we implement the constructor for Student explicitly, we can still call the constructor for Person if want:

Student::Student() : Person() { gpa = 0.0; }

(This can be done in the initialization list or in the method code.)

  • If a class is a friend of a base class, it gets access to the inherited attributes. If the base class is a friend of another class, the derived class is not necessarily a friend of that class.
  • Using call‐by‐value with polymorphic data can result in “slicing” of data. If we call a function and pass a Student by value into a Person parameter by value, the call will compile and run, but the parameter will not have all of the Student attributes. In that function, its type is Person.
  • Don’t make the destructor pure virtual. The derived class destructors need to call the base class destructor. Destructors are a special case in which the base class method is always called.

Casting

Note that to override a function, you need to use the exact same prototype for the function (with one exception). You cannot substitute a derived class for a base class parameter (or vice versa). For example, you can’t override: bool Person::operator<(const Person &p) const

with bool Student::operator<(const Student &p) const The parameter is different, so it is considered to be overloaded, not overridden.

We can implicitly cast from the derived class to the base class, but not vice versa. Let’s say that we want to implement a virtual operator< for people. If they are both students, we can order them by GPA. bool Student::operator<(const Person &p) const { const Student &s = static_cast<const Student &>(p); return gpa < s.gpa; }

We have to override the base class using a Person parameter to match the prototype for the virtual function and make the class non‐abstract. Inside the function, we have to cast to a Student, since only they have a GPA. What if the parameter is not a Student?

There is also a dynamic casting operation that does run‐time checking: const Student *s = dynamic_cast<const Student *>(p); If p is not a Student, then the dynamic cast will return NULL. This can be used to prevent casting pointers to other objects

into pointers to Students. Note that you must turn on RTTI (run‐time type information) to use dynamic_cast in Visual C++ (Properties – C/C++ – Language – Enable Run‐Time Type Info). This works with references, too. However, C++ doesn’t have NULL references, so dynamic_cast throws an exception if you try to call it with an incorrect parameter.

There is one exception to the rule about having the same prototype. You are allowed to return a pointer or reference to a derived class object instead of the base class. This facilitates operations such as clone.

Multiple inheritance

We saw above that we can inherit from multiple base classes. This can be tricky and should be used only when necessary.

class rhombus; class rectangle;

class square: public rhombus, public rectangle {…};

One issue that can arise is that both base classes may define a particular method. You need to be able to specify which one to use. For example, if both the rhombus and rectangle class had a method foo, then we could use: mySquare->rhombus::foo();

Summary

Inheritance is a useful tool for extending classes, allowing code reuse, and writing general containers (your BSTree is

general to any class that inherits from Object, with some minor modifications). Polymorphism allows objects to have different behaviors depending on the run‐time binding of a variable. However, it is important to use virtual functions to ensure polymorphic behavior.