280 likes | 482 Views
Junaed Sattar October 22, 2008 Lecture 8. Inheritance. 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
E N D
Junaed Sattar October 22, 2008 Lecture 8 Inheritance
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 class int 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: • Single Inheritance (SI) • only one parent per derived class • requires a small amount of run-time overhead when used with dynamic binding • Multiple inheritance • More than one parent per derived class • Compared with SI, MI adds additional run-time overhead (also involving dynamic binding)
Flow Schematic Image Source Webcam Image Source FireWire Image Source Disk Files Image Source Movie Files Processing Output to Robot (Image/Faces/Objects) Color Tracking Gesture Recognition Diver Detection Visual Localization
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
See the class inheritance diagram for RoboDevel “Real-world” example #2
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