hierarchy in c++ lecture 13 inheritance · pdf filelecture 13 inheritance tuesday, 16 february...

9
Lecture 13 Inheritance Tuesday, 16 February 2010 Hierarchy in C++ Hierarchy is a ranking and ordering of abstractions Two hierarchical schemes in OO : 'Is part of' - the object is a part of a larger object e.g. Engine is part of a car 'Is a' is also known as 'inheritance' we can see this when looking at the hyper- graph in Maya showing how all the different objects in a scene are connected together (especially when using groups, or I.K. chains) Tuesday, 16 February 2010 Composition (is part of) In C++ composition is a class that contains references to other classes We have been using this a number of times when using classes in the graphics library As well as when designing our own classes The next example shows this in action Tuesday, 16 February 2010 The particle Class is an aggregation of the classes on the right 1 class Particle 2 { 3 public : 4 5 ngl::Vector m_pos; 6 ngl::Vector m_dir; 7 ngl::Colour m_colour; 8 float m_life; 9 10 Particle( 11 ngl::Vector _pos, 12 ngl::Vector _dir, 13 ngl::Colour _colour, 14 float _life 15 ); 16 17 }; 1 class Vector 2 { 3 public : 4 Real m_x; 5 Real m_y; 6 Real m_z; 7 Real m_w; 8 9 10 Vector( 11 const Vector& _v 12 ): 13 m_x(_v.m_x), 14 m_y(_v.m_y), 15 m_z(_v.m_z), 16 m_w(_v.m_w){;} 17 }; 1 class Colour 2 { 3 public : 4 5 Real m_r; 6 Real m_g; 7 Real m_b; 8 Real m_a; 9 10 11 Colour( 12 const Colour& _c 13 ): 14 m_r(_c.m_r), 15 m_g(_c.m_g), 16 m_b(_c.m_b), 17 m_a(_c.m_a){;} 18 }; Tuesday, 16 February 2010

Upload: haphuc

Post on 13-Mar-2018

214 views

Category:

Documents


0 download

TRANSCRIPT

Lecture 13 Inheritance

Tuesday, 16 February 2010

Hierarchy in C++• Hierarchy is a ranking and ordering of abstractions

• Two hierarchical schemes in OO :

• 'Is part of' - the object is a part of a larger object

• e.g. Engine is part of a car

• 'Is a' is also known as 'inheritance'

• we can see this when looking at the hyper-graph in Maya showing how all the different objects in a scene are connected together (especially when using groups, or I.K. chains)

Tuesday, 16 February 2010

Composition (is part of)

• In C++ composition is a class that contains references to other classes

• We have been using this a number of times when using classes in the graphics library

• As well as when designing our own classes

• The next example shows this in action

Tuesday, 16 February 2010

The particle Class is anaggregation of theclasses on the right

1 class Particle2 {3 public :45 ngl::Vector m_pos;6 ngl::Vector m_dir;7 ngl::Colour m_colour;8 float m_life;9

10 Particle(11 ngl::Vector _pos,12 ngl::Vector _dir,13 ngl::Colour _colour,14 float _life15 );1617 };

1 class Vector2 {3 public :4 Real m_x;5 Real m_y;6 Real m_z;7 Real m_w;89

10 Vector(11 const Vector& _v12 ):13 m_x(_v.m_x),14 m_y(_v.m_y),15 m_z(_v.m_z),16 m_w(_v.m_w){;}17 };

1 class Colour2 {3 public :45 Real m_r;6 Real m_g;7 Real m_b;8 Real m_a;9

1011 Colour(12 const Colour& _c13 ):14 m_r(_c.m_r),15 m_g(_c.m_g),16 m_b(_c.m_b),17 m_a(_c.m_a){;}18 };

Tuesday, 16 February 2010

Inheritance

• In Object Oriented programming Inheritance allows us to form new classes based on pre-existing classes

• Usually this allows a form of specialisation of one type of object from the one being inherited

• This also allows us to create core functionality for object types and then extend them to specialist ones

Tuesday, 16 February 2010

Example A GUI

• The Above Qt GUI uses inheritance to give core features for each of the components then specialise for the actual widgets

• For example Each of the widgets have a core Attribute called geometry which specifies the size of the widget

• Can you think of some more?

Tuesday, 16 February 2010

Inheritance in C++

• The class that provides the basic functionality for an inherited object is usually called the Base

Class or Parent

• The inherited class is usually called the Derived or child class

• We can have many classes in an inheritance hierarchy each descended from the last

Tuesday, 16 February 2010

• Base Class has one attribute an integer x

• Two methods to set and get the value of x

• This class can be instantiated in the usual way and the methods called on the class

• At present there is no inheritance as we only have one class

1 class BaseClass2 {3 private :4 int m_x;56 public :78 inline void SetX(9 int _x

10 )11 {12 m_x=x;13 }1415 inline int GetX()16 {17 return m_x;18 }19 };

Tuesday, 16 February 2010

Adding a derived class• The derived class will inherit the attribute x from the

BaseClass and have access to the public methods setX and getX

• It will also extend the BaseClass by adding a new attribute y and methods setY and getY

• The derived class will now have two attribute X and Y and associated methods

• The syntax for a derived class to inherit the base class is as follows

1 class derived_class_name : public base_class_name

Tuesday, 16 February 2010

• The DerivedClass definition demonstrates the syntax for inheritance

1 class DerivedClass public : BaseClass2 {3 private :4 int m_y;56 public :78 inline void SetY(9 int _y

10 )11 {12 m_y=_y;13 }1415 inline int GetY()16 {17 return m_y;18 }19 };

Tuesday, 16 February 2010

• base_object is the base class and only has an x attribute

• derived_object has both x and y attributes

• note they are both different objects so x in base is different from x in derived

1 #include <iostream>2 #include <cstdlib>34 int main()5 {67 BaseClass BaseObject;8 DerivedClass DerivedObject;9

10 BaseObject.SetX(7);11 DerivedObject.SetX(10);12 DerivedObject.SetY(1);1314 return EXIT_SUCCESS;1516 }

Tuesday, 16 February 2010

Accessing inherited attributes• In the previous class the derived object cannot

directly access the attributes of the base class

• This is because they are in the private part of the class definition

• The derived class can only use the methods in the public definition of the base class

• This means the following code in the derived class would not compile

m_x is not part of DerivedClass

1 void DerivedClass::XequalsY()2 {3 m_x=m_y;4 }

Tuesday, 16 February 2010

The protected keyword

• To allow a derived class to access the attributes of the base class the attributes can be moved into the protected area

1 class BaseClass2 {3 protected :4 int m_x;56 ..........78 };9

1011 class DerivedClass : public BaseClass12 {1314 .......1516 void XequalsY()17 {18 m_x=m_y;19 }2021 };

Tuesday, 16 February 2010

Inheriting Constructors• A derived class will always inherit the constructor

of the base class

• A derived class will also have it's own constructor

• The base class constructor is called first followed by each derived class going down the hierarchy tree

• This is because each class constructor must allocate the memory required for the attributes of the class

• If the constructor for the base class has parameters then the derived class must have a constructor of the same type so that it may follow up the hierarchy tree

Tuesday, 16 February 2010

Inheriting destructors• Derived Classes also inherit the base classes

destructors

• However destructors are called in reverse order to the constructors

• So all the derived classes destructors are called first

• And the base class destructor is called last

• As destructors have no parameters there is now problem with the definition of correct parameter lists

Tuesday, 16 February 2010

Example

• The following example creates an inheritance hierarchy with 3 classes

• The Parent is the Base Class

• ChildA inherits from the parent

• ChildB inherits from ClassA and the Parent

int m_a

Parent

int m_b

ChildA

int m_c

ChildB

Tuesday, 16 February 2010

1 #ifndef __PARENT_H__2 #define __PARENT_H__34 class Parent5 {6 protected :7 int m_a;8 public :9 Parent(int _a);

10 ˜Parent();11 void Print();12 };1314 #endif

1 #include <iostream>2 #include "Parent.h"34 Parent::Parent(int _a)5 {6 std::cout <<"Parent ctor called"<<std::endl;7 m_a=_a;8 }9

10 Parent::˜Parent()11 {12 std::cout <<"Parent dtor called"<<std::endl;13 }1415 void Parent::Print()16 {17 std::cout <<"m_a = "<<m_a<<std::endl;18 }

int m_a

Parent

Tuesday, 16 February 2010

1 #ifndef __CHILDA_H__2 #define __CHILDA_H__34 #include "Parent.h"56 class ChildA : public Parent7 {8 protected :9

10 int m_b;1112 public :1314 ChildA(15 int _a,16 int _b17 );1819 ˜ChildA();20 void Print();2122 };2324 #endif

1 #include <iostream>23 #include "ChildA.h"45 ChildA::ChildA(6 int _a,7 int _b8 ) :9 Parent(_a)

10 {11 std::cout <<"ChildA ctor called"<<std::endl;12 m_b=_b;13 }1415 ChildA::˜ChildA()16 {17 std::cout <<"dtor for ChildA called"<<std::endl;18 }19 void ChildA::Print()20 {21 std::cout <<"m_a= "<<m_a<<" m_b= "<<m_b<<std::endl;22 }

int m_a

Parent

int m_b

ChildA

Tuesday, 16 February 2010

1 #ifndef __CHILDB_H__2 #define __CHILDB_H__34 #include "ChildA.h"567 class ChildB : public ChildA8 {9 protected :

10 int m_c;11 public :12 ChildB(13 int _a,14 int _b,15 int _c16 );17 ˜ChildB();18 void Print();19 };2021 #endif

1 #include <iostream>23 #include "ChildB.h"4567 ChildB::ChildB(8 int _a,9 int _b,

10 int _c11 ):12 ChildA(_a,_b)13 {14 std::cout <<"ChildB ctor called"<<std::endl;15 m_c=_c;16 }1718 ChildB::˜ChildB()19 {20 std::cout <<"ChildB dtor called"<<std::endl;21 }2223 void ChildB::Print()24 {25 std::cout <<"m_a="<<m_a<<" m_b="<<m_b;26 std::cout <<" m_c="<<m_c<<std::endl;27 }2829

int m_a

Parent

int m_b

ChildA

int m_c

ChildB

Tuesday, 16 February 2010

1 #include "Parent.h"2 #include "ChildA.h"3 #include "ChildB.h"45 #include <iostream>6 #include <cstdlib>789 int main(void)

10 {11 std::cout <<"Creating New Parent"<<std::endl;12 Parent *a = new Parent(2);13 a->Print();14 std::cout <<"\nDONE\n";1516 std::cout <<"Creating New ChildA"<<std::endl;17 ChildA *b= new ChildA(1,2);18 b->Print();19 std::cout <<"\nDONE\n";2021 std::cout <<"Creating New Child B"<<std::endl;22 ChildB *c= new ChildB(1,2,3);23 c->Print();2425 delete c;26 delete a;27 delete b;2829 return EXIT_SUCCESS;30 }

Tuesday, 16 February 2010

1 Creating New Parent2 Parent ctor called3 m_a = 245 DONE6 Creating New ChildA7 Parent ctor called8 ChildA ctor called9 m_a= 1 m_b= 2

1011 DONE12 Creating New Child B13 Parent ctor called14 ChildA ctor called15 ChildB ctor called16 m_a=1 m_b=2 m_c=317 ChildB dtor called18 dtor for ChildA called19 Parent dtor called20 Parent dtor called21 dtor for ChildA called22 Parent dtor called

Create a parentOnly Parent methods called

Create a ChildAThis calls the parent ConstructorThen the ChildA one.Note Destructors called in reverse order

The final one calls all 3Note the sequence of ctor / dtor calls

Tuesday, 16 February 2010

Multiple Children

• In this case we have multiple children

• The parent class has an attribute called Name as do the Children.

• These are however different attributes and the Parents name attribute can be access using the scope resolution operator ::

string m_nameParent

string m_nameSon

string m_nameDaughter

Tuesday, 16 February 2010

1 #ifndef __PARENT_H__2 #define __PARENT_H__34 #include <iostream>56 class Parent7 {8 protected :9 std::string m_name;

10 public :11 Parent(12 const std::string &_a13 );14 ˜Parent();15 void Print();16 };1718 #endif

1 #ifndef __DAUGHTER_H__2 #define __DAUGHTER_H__34 #include "Parent.h"56 class Daughter : public Parent7 {8 protected :9 std::string m_name;

10 public :11 Daughter(12 const std::string &_a,13 const std::string &_b14 );15 ˜Daughter();16 void Print();1718 };1920 #endif

1 #ifndef __SON_H__2 #define __SON_H__34 #include "Parent.h"56 class Son : public Parent7 {8 protected :9 std::string m_name;

10 public :11 Son(12 const std::string &_a,13 const std::string &_b14 );15 ˜Son();16 void Print();1718 };1920 #endif

Tuesday, 16 February 2010

1 #include "Son.h"23 Son::Son(4 const std::string &_a,5 const std::string &_b)6 : Parent(_a)7 {8 std::cout <<"Son ctor called"<<std::endl;9 m_name=_b;

10 }1112 Son::˜Son()13 {14 std::cout <<"dtor for Son called"<<std::endl;15 }16 void Son::Print()17 {18 std::cout <<"My name is "<<m_name;19 std::cout <<" my parent is "<<Parent::m_name<<std::endl;20 }

1 #include "Parent.h"23 Parent::Parent(4 const std::string &_a5 )6 {7 std::cout <<"Parent ctor called"<<std::endl;8 m_name=_a;9 }

10 Parent::˜Parent()11 {12 std::cout <<"Parent dtor called"<<std::endl;13 }1415 void Parent::Print()16 {17 std::cout <<"My Name is "<<m_name<<std::endl;18 }

Tuesday, 16 February 2010

1 Creating New Parent2 Parent ctor called3 My Name is DAD4 Parent dtor called56 Parent ctor called7 Son ctor called89 Parent ctor called

10 Daughter ctor called1112 My name is son my parent is Mother13 My name is daugter My parents name is Mother1415 dtor for Son called16 Parent dtor called1718 Daughter dtor called19 Parent dtor called

1 #include "Parent.h"2 #include "Son.h"3 #include "Daughter.h"45 #include <iostream>6 #include <cstdlib>789 int main(void)

10 {11 std::cout <<"Creating New Parent"<<std::endl;12 Parent *a = new Parent("DAD");13 a->Print();14 delete a;1516 Son *son=new Son("Mother","son");17 Daughter *daughter = new Daughter("Mother","daugter");1819 son->Print();20 daughter->Print();2122 delete son;23 delete daughter;24 return EXIT_SUCCESS;25 }

Tuesday, 16 February 2010

Method Polymorphism

• In a monomorphic language there is always a one to one relationship between a function name and it's implementation

• In an O-O system (where functions are replaced by methods) the relationship may be one to many

• The name of the method becomes a more abstract concept covering a range of different implementations appropriate to different classes of objects.

function nameprint

1 1 function Implementation

method nameprint

MethodImplementation

1 n

Tuesday, 16 February 2010

Overloading Method Names• With class hierarchies methods of the base class are inherited by the

derived classes.

• For example a method defined in the base class may be called by any object of any derived class.

• However this is very restrictive if we can only use inherited methods in our derived classes

• For example our derived class may use a method from the base class which is not aware of attributes in the derived class.

• This means that we need to either re-write a new method in the derived class (using the same method name which is known as overriding)

• Or we extend the method in the derived class by first calling the base class method and then executing the derived class method code.

Tuesday, 16 February 2010

Abstract Methods• It may be that two derived objects methods do not have much in

common, but need the same name as their functionality are the same.

• In this case it makes no sense to define the method in the base class as the implementation will be different

• However this in not good practice as having overloaded methods names in different parts of the classification hierarchy without common root will mean that the method will be applied in an 'ad-hoc' way.

• This may not seem like an issue now but when we look at the use of dynamic objects it may cause problems

• To overcome this we use the method name in the base class as a sort of place holder to allow the correct sequence of methods to be called.

• This method will not have any functionality or implementation it just sits there and does nothing.

Tuesday, 16 February 2010

This is actually derived X

1 Base m_x =72 Base m_x =123 Derived m_y =24

1 #include <iostream>2 #include <cstdlib>34 #include "BaseClass.h"5 #include "DerivedClass.h"67 int main(void)8 {9

10 BaseClass base_object;11 DerivedClass derived_object;1213 base_object.SetX(7);14 derived_object.SetX(12);15 derived_object.SetY(24);1617 base_object.ShowX();18 derived_object.ShowX();19 derived_object.ShowY();2021 return EXIT_SUCCESS;22 }

1 #ifndef __BASECLASS_H__2 #define __BASECLASS_H__34 class BaseClass5 {6 private :7 int m_x;8 public :9 void SetX(

10 int _x11 );1213 void ShowX();14 };1516 #endif

1 #ifndef __DERIVEDCLASS_H__2 #define __DERIVEDCLASS_H__34 #include "BaseClass.h"56 class DerivedClass : public BaseClass7 {8 private :9 int m_y;

10 public :1112 void SetY(13 int _y14 );1516 void ShowY();1718 };1920 #endif

Tuesday, 16 February 2010

Overriding the derived Method

• The output from the derived class is incorrect as it says base m_x =12 where it should say derived m_x = 12

• To modify this output we need to override the ShowX method in the DerivedClass to do this we add the method definition to the DerivedClass

• We also need to make m_x protected in the base class

Tuesday, 16 February 2010

Extending Inherited methods

• In the previous example we applied polymorphism to override (replace) an inherited method definition

• We may also if we wish simply extend the definition of an inherited method by calling it in a derived class method and add in extra implementation detail.

• We do this in the ngl::Light and ngl::SpotLight classes as the two are very similar.

Tuesday, 16 February 2010

1 bool Light::Enable()2 {3 if (m_lightNo==0)4 {5 if (s_numEnabledLights==8)6 {7 std::cerr << "[WARNING] trying to enable more than 8 lights at once!" << std::endl;8 return false;9 }

10 // set light num11 m_lightNo = s_freeLights[s_numEnabledLights++];12 }13 // set GL params14 Real zero[] = {0.0f,0.0f,0.0f,0.0f};1516 GLint light=GL_LIGHT0+(m_lightNo-1);17 glLightfv(light,GL_DIFFUSE,m_colour.m_openGL);18 glLightfv(light,GL_SPECULAR,m_specColour.m_openGL);19 glLightfv(light,GL_AMBIENT,zero);20 m_pos.m_w=(Real)m_lightMode;21 glLightfv(light,GL_POSITION,m_pos.m_openGL);22 glEnable(light);2324 return true;25 }

Tuesday, 16 February 2010

1 bool SpotLight::Enable()2 {3 if(!Light::Enable())4 {5 return false;6 }7 GLint lightNo=GetLightNum();8 //std::cout <<lightNo<<std::endl;9 glLightf(lightNo, GL_CONSTANT_ATTENUATION, m_constantAtten);

10 glLightf(lightNo, GL_LINEAR_ATTENUATION, m_linearAtten);11 glLightf(lightNo, GL_QUADRATIC_ATTENUATION, m_quadraticAtten);12 glLightf(lightNo, GL_SPOT_CUTOFF, m_cutoffAngle);13 glLightfv(lightNo,GL_SPOT_DIRECTION, m_dir.m_openGL);14 glLightf(lightNo, GL_SPOT_EXPONENT, m_spotExponent);15 return true;1617 }

Call Light::Enable() in the base class then continue if successful

Tuesday, 16 February 2010

References

• http://www.parashift.com/c++-faq-lite/basics-of-inheritance.html

Tuesday, 16 February 2010