View
221
Download
0
Tags:
Embed Size (px)
Citation preview
Inheritance
Junaed SattarOctober 22, 2008
Lecture 8
OOP and Inheritance
OOP : the combination of Abstract Data Types (ADTs) with Inheritance and Dynamic Binding
ADTs decompose systems into two-dimensional grids of modules Each module has public and private
interfaces Inheritance decomposes systems into
three-dimensional hierarchies of modules
Formally...
mechanism of reusing and extending existing classes without modification produces hierarchical relationships almost like embedding one class into another
include the names and definitions of another class's members as part of a new class
Why inheritance?
write code to handle certain cases and allows others to write code that handles more specialized cases
partitions a system architecture into semi-disjoint components that are related hierarchically
ability to modify and/or reuse sections of the inheritance hierarchy without disturbing existing code
Overview
A type (called a subclass or derived type) can inherit the characteristics of another type(s) (called a superclass or base type)
A derived type acts just like the base type, except for an explicit list of: Specializations
Change implementations without changing the base class interface
Most useful when combined with dynamic binding Generalizations/Extensions
Add new operations or data to derived classes
Composition
class A {int data;
public:void f(int arg) { data = arg; }int g() { return data; }
};
class B { public: A x;};
int main() {B obj;obj.x.f(20);cout << obj.x.g() << endl;// cout << obj.g() << endl;
}
The Non-OOP way
How can we write obj.g(() legally? Rewrite another data structure:
Basically, copy-paste base code and add the new bits
What if the base code changes? Have to rewrite all the new classes
Inherited version
class A { // Base classint data;
public:void f(int arg) { data = arg; }int g() { return data; }
};
class B : public A{ // Inherited class};
int main() {B obj;obj.f(20);cout << obj.g() << endl;
}
Inherited class...
can add new methods and data members can modify implementation of existing
member functions and data, too technique known as overriding, used in
dynamic binding can be inherited again
Types of inheritance
Two forms based on number of parents:
1.Single Inheritance (SI) only one parent per derived class requires a small amount of run-time overhead
when used with dynamic binding
2.Multiple inheritance More than one parent per derived class Compared with SI, MI adds additional run-time
overhead (also involving dynamic binding)
Production code example
Flow Schematic
Image SourceWebcam
Image SourceFireWire
Image SourceDisk Files
Image SourceMovie Files
Processing
Color Tracking Gesture Recognition Diver Detection Visual Localization
Output to Robot(Image/Faces/Objects)
“Real-world” example #1
The catch?
May create deep and/or wide hierarchies that are hard to understand and navigate without class browser tools
May decrease performance slightly when combined with multiple inheritance and
dynamic binding Without dynamic binding, inheritance has
limited utility And dynamic binding is essentially pointless
without inheritance
“Real-world” example #2
See the class inheritance diagram for RoboDevel
In C++...
The class head is modified to allow a derivation list consisting of base classes class Foo { /* . . . */ }; class Bar : public Foo { /* . . . */ }; class FooBar : public Foo, public Bar { /* . . . */ };
Base and derived class pointers
A pointer to a derived class can be assigned to a pointer to any of its public base classes without requiring an explicit cast: Menu m; Window *w = &m; Screen *ps1 = w;Screen *ps2 = &m;
Casting
How about the other way? pointer casting from base to derived class is invalid (guess why?)
but it can be forced class CBase { };class CDerived: public CBase { };CBase b; CBase* pb; CDerived d; CDerived* pd;
int main(){ pb = &d; // ok: derived-to-base // valid syntax but based-to-derived
pd = (CDerived*)(&b); }
dynamic cast
to stop such disasters from happening, use dynamic_cast
pb = dynamic_cast<CBase*>(&d); // ok: derived-to-basepd = dynamic_cast<CDerived*>(&b);// not ok, and will generate // compiler error!
static cast
the old-fashioned C-way:int k = 10;double d = 10.11;
k = (int)d;//or k = int(d);
The new C++ way:k = static_cast<int>(d);
More static_cast-ing
class CBase { };
class CDerived: public CBase { };
CBase b; CBase* pb; CDerived d; CDerived* pd;
int main(){ pb = &d; // ok: derived-to-base // valid syntax but based-to-derived
pd = static_cast<CDerived*>(&b); }
Practical C++
Common practice to use header files declare class in header (.hh/.hpp/.h) define in source (.cpp/.cc/.cxx)
Benefits? hide implementation detail in source cpp file provide header file as an API to other
developers separate implementation from interface
How?
// this is ImageReader.hh
#ifndef IMAGEREADER_H_
#define IMAGEREADER_H_
class ImageReader{protected:
unsigned char *imageBuffer;std::string *pathString;unsigned iWidth, iHeight, iDepth;static const int FIRST_FRAME;
public:ImageReader();virtual ~ImageReader();bool OpenDirectory( const char *dir );bool GetFrame();bool RewindSequence();int GetFrameNumber();
};
#endif /*IMAGEREADER_H_*/
The source
// this is ImageReader.cc
#include <iostream>
#include "ImageReader.hh" // here's where we include the // declaration
const int ImageReader::FIRST_FRAME = 0; // constant definition
ImageReader::ImageReader(){std::cout << "Image reader loading..\n";}
... // the rest of the class
using the class
// this is main.cc
#include "ImageReader.hh" // here's where we include // the declaration
int main() {ImageReader reader;...
// do our stuff with reader here
}
“Building” the program
Two source files main.cc and ImageReader.cc
manual compilation with g++:
g++ main.cc ImageReader.cc -o mainProgram
Makefile
a simpler way to combine multiple source files with build rules, to produce one binary
very useful, when project contains many files, and many build rules debugging options, optimizations, libraries,
etc etc links to tutorials to makefiles on the
course website