View
222
Download
3
Tags:
Embed Size (px)
Citation preview
Inheritance• In our daily lives we use the concept of classes divided into subclasses, for example vehicles are divided into cars, trucks, buses and motor cycles.• The principle in this sort of division is that each sub-class shares some common features with the base class from which it is derived, but also has its own particular features.
Vehiclewheelsengine
Carwheelsenginetrunk
Truck
wheelsenginetrailertrunk trailer
base class
sub-classes orderived classes
Base Class Dateclass Date // declares class name{ private: int day, month, year; // member data public: // member functions void Date(int d, int m, int y); // constructor Date operator+(int days); Date& operator++(); int operator-(Date &date); bool LeapYear(); int DaysInMonth(); void Display();};
Derived Class DateTimeclass DateTime : public Date // derived from base class Date
{
private:
int hour, minutes; // additional member data
public: // additional member functions
void DateTime(int d, int m, int y, int h, int mi); // constructor
void SetTime(int h, int m);
void AddMinutes(int m);
void AddHours(int h);
void Display(); // overrides Date::Display()
};
Accessing Base Class Members
The access specifier private, protected and public specify which objects are allowed to access members of the base class
private: This member is only accessible within the
base class. protected:
This member is accessible within the base class and its derived classes.
public: Every object of the class outside the class
definition has access to this member
Accessing Base Class Members
Base class
private:
protected:
public:
Derived class
private:
protected:
public:
Derived object; Base object;
Inheritance vs. Composition
• Composition: • Composition is building objects from parts. • Composition denotes a has-a relationship• Composition is defined on the object level.• Example: A Car has an Engine
• Generalization:• Generalization is a relationship defined at the class
level not the object level, which means that all objects of this class must obey the relationship.
• Generalization denotes a is-a-kind-of relationship.• Example: A Car is a kind of Vehicle.
Inheritance Vehcie/Engine
class Engine
{
void StartEngine();
};
class Vehicle : public Engine // bad design
{
};
Vehicle volvo;
volvo.StartEngine();
Composition Vehicle/Engine
class Engine
{
void StartEngine();
};
class Vehicle : public Engine
{
private:
Engine engine;
public:
void Start() { engine.StartEngine(); }
};
Virtual Functions
Virtual functions allow the re-definition of base class functions in the derived class
The program decides at run-time not at compile time which version of a function is called (dynamic binding)
When virtual functions are used, a program that appears to be calling a function of one class may in reality be calling a function of a different class
Static Binding
class Animal
{
protected;
string str;
public:
Animal(const string s) : str(s) {};
void Display() { cout << ”Animal : ” << str << endl; }
// non-virtual function, static binding
};
Derived Classes
class Dog : public Animal
{
public:
Dog(const string s) : Animal(s) {};
void Display() { cout << ”Dog : ” << str << endl; }
};
class Cat : public Animal
{
public:
Cat(const string s) : Animal(s) {};
void Display() { cout << ”Cat : ” << str << endl; }
};
Static Binding
Animal *zoo[3]; // defines an array of pointers to Animal
Animal animal(”Flipper”); // creates an Animal object
Dog dog(”Lassie”); // creates a Dog object
Cat cat(”Jerry”); // creates a Cat object
zoo[0] = &animal; // pointer zoo[0] points to animal
zoo[1] = &dog; // pointer zoo[0] points to animal
zoo[2] = &cat; // pointer zoo[0] points to animal
for (int i=0; i<3; i++)
zoo[i]->Display(); // static binding to Animal::Display()
Output:
Animal : Flipper
Animal : Lassy
Animal : Jerry
Static BindingAnimal
Display()zoo[0]->Display();
zoo[1]->Display();
zoo[2]->Display();
Dog
Display()
Cat
Display()
Virtual Function
class Animal
{
protected;
string str;
public:
Animal(const string s) : str(s) {};
virtual void Display() { cout << ”Animal : ” << str << endl; }
// virtual function, dynamic binding
};
Dynamic Binding
Animal *zoo[3]; // defines an array of pointers to Animalzoo[0] = new Animal(”Flipper”); // creates an Animal objectzoo[1] = new Dog(”Lassie”); // creates a Dog objectzoo[2] = new Cat(”Jerry”); // creates a Cat objectfor (int i=0; i<3; i++)
zoo[i]->Display(); // dynamic binding to either // Animal::Display(), Dog::Display() or Cat::Display()
Output:Animal : FlipperDog : LassyCat : Jerry
Dynamic BindingAnimal
Display()zoo[0]->Display();
zoo[1]->Display();
zoo[2]->Display();
Dog
Display()
Cat
Display()
Dynamic Binding with References
void f(Animal& a){ cout << ”This is an ”; a.Display();}
Animal animal(”Flipper”);Dog dog(”Lassie”);Cat cat(”Jerry”);f(animal);f(dog);f(cat);
Dynamic Binding
#include <vector>Dog d(”Lassie”);Animal *a=&d; // defines a pointer of Animal that points to dAnimal &someanimal=d; // OKAnimal &anyanimal; // ERROR reference must be initializedvector<Animals*> animals; // OKanimals.push_back(&d); // add element pointer to d
Abstract Classes
Assume you have a class library for graphics objects. All classes like Circle, Rectangle, Line etc. inherit from a base class Shape.
Shape is an abstraction of properties that all graphical elements have in common.
But there will never be an object of the Shape class itself, we will only make specific shapes such as circles and triangles.
As class that only acts as a base class for other classes is called an abstract class.
Pure Virtual Function
A base class becomes an abstract class if it contains at least one pure virtual function.
A pure virtual function remains undefined in the base class but has to be overloaded by its subclasses.
A pure virtual function must be overloaded by the subclass whereas a virtual function can be overloaded by subclasses.
A pure virtual function is one with the expression =0 added to the declaration.
Graphic Operations
Move(dx,dy)dx,dy
Rotate(phi,P(x,y)) P(x,y)
RotateShape(phi)
P(x,y) Center()
Abstract Base Class Shape
class Point;
class Shape // abstract base class
{
virtual void Draw()=0; // pure virtual function
virtual void Move(double dx, double dy)=0; // move figure
virtual void Rotate(double phi)=0; // rotate figure around P=(0,0)
virtual Point Center()=0; // return center of figure
virtual void Rotate(int phi, Point p); // non-virtual: rotate
virtual RotateShape(); // rotate around center of figure
// around a Point p by angle p)
};
Abstract Base Class Shape
void Shape::RotateShape(double angle)
{
Rotate(angle,Center()); // rotate shape around its own center
}
void Shape::Rotate(double angle, Point p)
{
Move(-p.GetX(),-p.GetY()); // move Shape so P is in (0,0)
Rotate(angle); // rotate around P(0,0) by angle degrees
Move(p.GetX(),p.GetY()); // move Shape back to by x,y
}
SubClass Pointclass Point : public Shape // subclass inherits from Shape
{
public:
Point(double nx, double ny) : x(nx), y(ny) {} // constructor
virtual void Draw(); // draw a point
virtual void Move(double dx, double dy) {x+=dx; y+=dy;}
virtual void RotateShape(double phi) {} // nothing happens
virtual void Rotate(double angle); // rotate P around (0,0)
virtual Point Center() {return *this;} // return center of point
double GetX() { return x;}; double GetY() { return y;}
private:
double x,y;
};
SubClass Point#include <math.h>
virtual void Point::Rotate(double angle) // rotate P around (0,0)
{
double nx=(cos(angle)*x-sin(angle)*y);
double ny=(sin(angle)*x+cos(angle)*y);
x=nx;
y=ny;
}
virtual void Point::Draw()
{
cout << “<“ << x << “,“ << y << “>”; // ohhhh... how boring
}
SubClass Lineclass Line : public Shape // subclass inherits from Shape
{
public:
Line(Point np1, Point np2) : p1(np1), p2(np2) {} // constructor
virtual void Draw(); // draw a line
virtual void Move(double dx, double dy);
virtual void Rotate(double angle); // rotate P around (0,0)
virtual Point Center() {return (p1+p2)/2.0;}
private:
Point p1,p2;
};
SubClass Linevirtual void Line::Draw() {
p1.Draw();
p2.Draw();
}
void Line::Move(double dx, double dy) {
p1.Move(dx,dy);
p2.Move(dx,dy);
}
virtual void Line::Rotate(double angle) {
p1.Rotate(angle);
p2.Rotate(angle);
}
;
Using Shapes
Shape *shapes[4]; // stores four pointers to shapes
shapes[0] = new Point(3.0,8.9);
Point p1(7.2,5.6);
Point p2(6.5,2.3);
Point p3(3.4,1.0);
shapes[1]= new Line(p1,p2);
shapes[2]=new Triangle(p1,p2,p3);
shapes[3]=new Rectangle(p2,p3,p1,*shapes[0]);
Compound Shapeclass CompoundShape : public Shape
{
public:
CompoundShape(Point p) { center=p; }
void AddShape(Shape &s);
virtual void Draw();
virtual void RotateShape(double angle);
virtual Point Center() { return center; }
private:
vector<Shape *> shapes;
Point center;
};
Compound Shapevoid CompoundShape::AddShape(Shape &s)
{
shapes.push_back(&s);
}
virtual void Draw()
{
vector<Shape*>::iterator iter;
for(iter=shapes.begin();iter!=shapes.end();iter++)
*iter->Draw(); // de-reference twice !!!
}
Compound Shapevoid CompoundShape::RotateShape(double angle)
{
vector<Shape*>::iterator iter;
for(iter=shapes.begin();iter!=shapes.end();iter++)
*iter->Rotate(angle,Center());
// rotate around center of compound !!!
}
Overloading Assignment
Using the assignment symbol a2=a1;
causes the compiler to copy the data from a1, member by member into a2. This is the default action of the assignment operator =.
However, there might be situations in which you want the assignment operator to behave differently, for example if your data member is a pointer to objects you might want to replicate the objects itself as well not just the pointers.
Linked List Examplestruct link // one element of list{ int data; // data item link *next; // pointer to next element};
class linklist{ private:
link* first; // pointer to first link public:
linklist() { first = NULL;} // no argument constructor void additem(int d); // add data item (one link) void display(); // display all links}
Linked List Examplevoid linklist::additem(int d) // add data item{ link* newlink = new link; // create a new link newlink->data = d; // give it data d newlink->next=first; // it points to the next link first = newlink; // now first points to this link}void linklist::display() // display all links{ link* current=first; // set ptr to first link while(current != NULL) // until ptr points beyond last link { cout << current->data << ” ”; // print data current=current->next; // move to next link } }
Linked List Example
void linklist::deleteitem() // delete first data item{ link* tmp=first->next; // tmp to remember pointer to 2nd element delete first; // deletes first link from memory first=tmp; // old second element becomes new first element}
Linked List Example Assume you assign one list to another, with
the default assignment operator only the pointer to the first link gets copied.
linklist l1;
l1.additem(3);
l1.additem(5);
l1.additem(2);
2 5 3l1
Linked List Examplelinklist l1;
l1.additem(3);
l1.additem(5);
l1.additem(2);
linklist l2;
l2=l1;
2 5 3l1
l2
2 5 3l2
Overloading Assignment
linklist& linklist::operator=(linklist &list) // assignment operator{ while (first !=NULL) // first empty list deleteitem();
link* current=list.first; // set ptr to first link while(current != NULL) // until ptr points beyond last link { additem(current->data); // print data current=current->next; // move to next link } first=current; return *this; }
Murphy’s Lawlinklist l1;
l1.additem(3);
l1.additem(5);
l1.additem(2);
l1=l1; // ooouuuch !!!! l1 deletes itself
linklist& linklist::operator=(linklist &list) // assignment operator{ if (this == &list) // both arguments to = are the same object return *this; …}
Copy Constructor You can define and at the same time initialize an object
to a value of another object with two kinds of statements.linklist l1(l2); // copy initialization
linklist l1=l2; // copy initialization not assignmentl1=l2; // assignment operator =
class linklist{ public:
linklist() { first = NULL;} linklist( linklist& list) { *this=list; } // copy constructor … };
Multiple Inheritance
base class A
Feature B
Feature A
subclass
Feature B
Feature A
Feature C
Feature D
base class B
Feature D
Feature C
Multiple Inheritance
class Date
{
private:
int day, month, year;
…
};
class Time
{
private:
int hours, minutes;
…
};
Multiple Inheritance
class DateTime : public Date, public Time
{
public:
DateTime(int d, int m, int y, int h, int mi)
: Date(d,m,y), Time(h, mi) {};
…
};
Ambiguity in Multiple Inheritance
class Date
{
void add(int days);
};
class Time
{
void add(int minutes);
};
DateTime dt(13,2,1998,23,10);
dt.add(3); // ambiguous -- will not compile
dt.Date::add(4); // uses add of class Date
dt.Time::add(5); // uses add of class Time
Ambiguity in Multiple Inheritance
class A { public: void F(); };
class B : public A { …};
class C : public A { …};
class D : public B, public C {};
D d;
d.F(); // ambiguous - won´t compile
class A
class B class C
class D
diamond shapedinheritance tree