Interra Induction Training Programming in C++ Kolkata, July 11, 2006 Camp 06 Maturing Minds
Object Oriented Programming in C++ Inheritance
Topics to be discussed Fundamentals of Inheritance protected Access Specifier Initialization Virtual Functions CAMP 06: Maturing Minds
Reusability Reuse an already tried and tested code Advantages: Reduces cost & development time. Improves quality C Style Code Reuse Library Function Disadvantage: Reuse cannot be customized C++ Style Reuse: Inheritance Composition CAMP 06: Maturing Minds
Basics of C++ Inheritance If a class A is derived from another class B then A is called the derived/sub class and B is called the base/super class. All (?) data members and methods of the base class are immediately available to the derived class. Thus, the derived class gets the behavior of the base class The derived class may extend the state and behavior of the base class by adding more attributes and methods. CAMP 06: Maturing Minds
Accessibility of Base Class Members What happens to the access specifier of the members of the base class when they are derived? Depends on the mode of derivation. In public inheritance, private members of the base class become private members of the derived class and public members of the base class become public members of the derived class However, private members of the base class are not directly accessible to the members in the derived class. CAMP 06: Maturing Minds
Object Layout in Inheritance Assume the following class hierarchy class C: public B { .. }; class B: public A class A Layout for an object of type C A - Part Data Member B-Part Data Member C-Part Data Member CAMP 06: Maturing Minds
protected Members private data members of the base class cannot be directly accessed by the methods of the derived class. However, it is important for the derived class to have more accessibility to the members of the base class than other classes or functions. If a member is protected then it is directly accessible to the methods of the derived class. CAMP 06: Maturing Minds
Syntax of Inheritance An example class Employee { protected: float basic; long id; public: Employee(long id); float getSalary(); }; class Manager : public Employee Employee *supervised[10]; int numberOfPeopleManaged; Manager(Id, n); void printSupervisedEmployeeId(); } CAMP 06: Maturing Minds
Order of Constructor Calls The constructor of the derived class is responsible for initializing the state of the derived object. The derived object contains attributes which are inherited by the derived class. The constructor of the derived class calls an appropriate constructor of the base class Therefore, the constructor of the base class is executed first and then the constructor of the derived class is executed. CAMP 06: Maturing Minds
Example of Derived Class Constructor Employee::Employee(long id) { this->id = id; } Manager::Manager(long id, int n) : Employee(id) numberOfPeopleManaged = n; CAMP 06: Maturing Minds
Order of Destructor Calls The destructor of the derived class is responsible for cleaning up the state of the derived object. The derived object contains attributes which are inherited by the derived class. The destructor of the derived class calls the destructor of the base class Therefore, the destructor of the base class is executed first and then the destructor of the derived class is executed. CAMP 06: Maturing Minds
Casting Derived class pointer can be implicitly cast to a base class pointer Manager m; Employee *e = &m; // Employee *e = (Employee *)(&m); Only base class part of the derived object can be seen through the base pointer. e-> printSupervisedEmployeeId(); //error A Base class pointer cannot be implicitly cast to a derived class pointer Manager *pM; pM = e; //error pM = (Manager *)e; //ok Down casting may be dangerous CAMP 06: Maturing Minds
Static vs. Dynamic Binding Binding refers to associate a type to a name. Consider the following example: Manager m; Employee *e = &m; e->getSalary(); //Which getSalary? Employee or Manager? “e” is declared as a pointer to Employee In the example however, it makes more sense to mean “getSalary” of the Manager class. We need a dynamic binding of “e” so that the type of “e” may be set at run time by pointer to the type of the actual object This is also called late binding CAMP 06: Maturing Minds
Virtual Functions In C++, dynamic binding is made possible only for pointer & reference data types and for methods that are declared as virtual in the base class. If a method is declared as virtual, it can be overridden in the derived class. If a method is not virtual and it is re-defined in the derived class then the latter definition hides the former one. CAMP 06: Maturing Minds
Virtual Function: Example class X{ class Y: public X{ public: public: int f(){ return 2; } int f(){ return 4;} virtual int g(){ return 3;} int g(){ return 6;} }; }; main() { Y a; int i, j , k, m; X *b; b = &a; i = b->f(); j = a.f(); k = b->g(); m = a.g(); printf(“%d %d %d %d\n”, i, j, k, m); } Output will be 2 4 6 6 CAMP 06: Maturing Minds
Redefining a Non-Virtual Function Simply do not do that. class X() class Y : public X { { protected: protected: void f(); void f(); }; }; int main() { Y y1; Y *pY; X *pX; pX = &y1; pX->f(); // f as defined in X will be called pY = &y1; pY->f(); // f as defined in Y will be called } CAMP 06: Maturing Minds
Virtual Function Table If a class has a virtual function, then each instance of that class contains a space to store a pointer to the actual definition of that function. During creation, the actual address of the function is assigned to the function pointer. Y is derived from X, which has a virtual function. X-part-data X-part-virtual-function-ptr Y-part-data Actual definition of the virtual function CAMP 06: Maturing Minds
Abstract Class Pure Virtual Function A virtual function may be assigned to NULL meaning that this function is declared but not defined in a class. Definition of such a class is incomplete. A class with one or more pure virtual function is called an abstract class. Abstract class cannot be instantiated. Abstract class define a contract or interface to be used by the user of the class library and to be implemented by the developer of the class library. CAMP 06: Maturing Minds
Virtual Destructor Constructors cannot be virtual For a base class which has been derived from, the destructor must be declared virtual. Occasionally we create a derived object and store it using a pointer to Base class such as Base *pBase = new Derived(/*arguments*/); If we destroy this object using “delete pBase” then two destructors need to be called. If the destructor in the Base class is not declared virtual then the destructor of the Derived class will not be automatically called in this example. CAMP 06: Maturing Minds
Inheritance Example: Polymorphic Array Consider an abstract base class Shape which contains a pure virtual function “CalculateArea”. Suppose three classes Triangle, Rectangle and Circle derived from Shape. Consider a main function that creates different Shape objects and store them in an array. If in a for loop the function calculateArea is called on all objects in the array, we see dynamic binding in use. CAMP 06: Maturing Minds
Polymorphic Array: Class Definitions class Shape { public: virtual double calculateArea() = 0; }; class triangle : public Shape() private: Point a, b, c; Triangle(double x_a, double y_a, double x_b, double y_b, double x_c, double y_c); double calculateArea(); class Circle : public Shape() { private: Point centre; double radius; Circle(double x_centre, double y_centre, double r);, public: double calculateArea(); }; CAMP 06: Maturing Minds
Polymorphic Array: main function int getInput(Shape *pArr) { int i, double x_a, x_b, x_c, y_a, y_b, y_c; scanf(“%d”, &i); while (1) switch (i) case 0: break; case 1: scanf(“%f%f%f%f%f%f”, &x_a, &y_a, &x_b, &y_b, &x_c, &y_c); pArr[I] = new Triangle(&x_a, i++; break; …….. } int main() { Shape *pArr = NULL; int n = 0; n = getInput(pArr); int i; for (i = 0; i < n; i++) double area = Shape[i]->calculateArea(); printf (“%lf \n”, area); } int getInput(Shape *pArr) printf(“Which Shape do you want to create?\n”); printf(“Write 1 for triangle, 2 for rectangle, 3 for circle and 0 to quit\n”); CAMP 06: Maturing Minds
Inheritance: Benefits Code Sharing/Reuse Consistency of Interface Construction of Software Components Rapid Prototyping Information Hiding CAMP 06: Maturing Minds
Inheritance: Cost Execution Speed Program Size Message Passing Overhead Program Complexity CAMP 06: Maturing Minds
Inheritance: Limitations operator= cannot be inherited Can be used to assign objects of the same type only Copy Constructor cannot be inherited Static members are inherited in a derived class Static members cannot be “virtual” If you redefine a static member function, all other overloaded functions in the base class are hidden CAMP 06: Maturing Minds
Interra Induction Training Object Oriented Programming in C++ More on Inheritance Kolkata, July 22, 2005
Inheritance Notes Constructors cannot be virtual Calling a virtual function from within a constructor does not have the desired effect. The following code is buggy. Tell why. void f(Base *b) int main() { { b[0].f(); b[1].f(); Derived d[10]; } f(d); } Derived is publicly derived from Base. Class Base has a virtual function “f” which is redefined in Derived. CAMP 06: Maturing Minds
Default Parameter & Virtual Function You should not change the default parameter in a redefined virtual function class X() class Y : public X { { protected: protected: virtual void f(int i = 10); virtual void f(int i =20); }; }; int main() { Y y1; Y *pY; X *pX; pX = &y1; pX->f(); // f with value of i as 10 will be called pY = &y1; pY->f(); // f with value of i as 20 will be called } CAMP 06: Maturing Minds
Is an Ostrich a Bird Suppose there is a base class Bird a virtual method fly returns altitude > 0. A class Ostrich is derived from Bird. fly method has to be redefined as an empty function. Leads to a logical dilemma. Can an overridden method be empty? Can an overridden method throw exceptions? CAMP 06: Maturing Minds
Is a Circle an Ellipse? Circle is a special type of ellipse. Let Circle be derived from Ellipse. Suppose that Ellipse has a method setSize(x,y). Also suppose that there is a function sample as defined below. sample (Ellipse &e) { e. setSize(10,20); ……. } If sample is called on a circle, strange things happen! Subset is not substitutable!! CAMP 06: Maturing Minds
Should a Stack inherit from a List? Probably Not! If List is the base class of Stack Methods such as push, pop etc. are to be defined (at least as pure virtual) in the List class. All members of List must have (even a trivial) implementation in Stack. A Stack has a List. CAMP 06: Maturing Minds
Multi-level Inheritance Suppose that C is derived from B and B is derived from A. Suppose that a method, f, in A is virtual. If f is redefined in B then f is virtual even if the keyword “virtual” does not precede the declaration/definition in the derived class. It is advisable to explicitly write “virtual” in front of the definition of f in B as, otherwise, an implementer of C may think that f is not a virtual method. CAMP 06: Maturing Minds
Inheritance & Code Reuse Suppose that C and B and are derived from A. Both C and B contain a function f ; therefore, f is made a virtual (not pure) function in A. This is bad. A new class D is required to be derived from A later. f in D is different than A. Interfaces should not have implementation. CAMP 06: Maturing Minds
private Inheritance If B is privately derived from A then private, protected and public members of A become private members of B. However, private members of A are not directly accessible to B. Thus, even if C is publicly derived from B then no member of A is accessible to C. Functions which may access members of A in B are Methods of class B Friend functions of class B. CAMP 06: Maturing Minds
protected Inheritance If B is protectedly derived from A then, protected and public members of A become protected members of B. However, private members of A remain private in B and are not directly accessible to B. Functions which may access members of A in B are Methods of class B Friend functions of class B. Methods in classes publicly derived from B Friend functions of classes publicly derived from B CAMP 06: Maturing Minds
Private Inheritance: Implications public Inheritance models “is a” private inheritance models “is implemented in terms of ” Assume two classes, Set and List. Set contains unique elements while List may contain duplicate elements. Thus Set is not a List But a Set can use the code of the List class as a Set can be implemented in terms of a list. Users of the class Set should not have an access to the List behavior even to create further derived classes CAMP 06: Maturing Minds
Interra Induction Training Object Oriented Programming in C++ Exceptions Kolkata, July 22, 2005
Topics Basic Concept of Exceptions try-catch block in C++ Semantics of throw CAMP 06: Maturing Minds
Error Handling in C++ Error Condition Handling - C Style via return value return statement is dedicated for passing error conditions by output parameter normal and abnormal control flow tend to mix Reusing code for error handling is difficult. Error Condition Handling - C++ Style On error condition an exception object is created and thrown. A function catches exception objects generated from the function it calls in a distinct control flow. Similar Exception objects can enjoy benefits of inheritance. CAMP 06: Maturing Minds
C-Style Error Handling int Calculator::divide (int i) { if (i == 0) // what do we do? } else value /= i; return value; A Calculator need to handle divide by zero Could set value to NAN But, program would need to check for special value (and might ignore) Could return –1 Again program could ignore Might be a valid return value CAMP 06: Maturing Minds
“try” and “catch” A function has its usual prototype and it may throw a number of exceptions on detecting several error condition. “try” block encloses code that has usual flow of control and can potentially throw exceptions “catch” block can occur after a “try” block or another “catch” block catch blocks can catch and handle exceptions of different types CAMP 06: Maturing Minds
Exception Object and throw Exception object is just another object having members (attributes and methods) suitable to model the state and behavior of an object representing an error condition. Whenever an error condition is detected, a suitable Exception object is thrown.Semantics of throw is as follows. Creation of an object (function of new) passing control from this function to the caller function (similar to return) Unlike return, throw initiates unwinding of the call stack till the exception is handled. CAMP 06: Maturing Minds
Example of Exception Handling in C++ class DivideByZero{ private: int dividend; public: print() { cout << dividend << “is divided by zero” <<endl; } DivideByZero(int d) { dividend = d; } }; int Calculator::divide(int i) throws DivideByZero { if (I ==0) throw DivideByZero(value); value /= I; return value; int main (int argc, char **argv) { int i = 0; Calculator c; try c.divide (0); cout << c.getValue (); } catch (DivideByZero ext) ex.print(); return 1; return 0; CAMP 06: Maturing Minds
Details of throw Normal program control flow is halted At the point where an exception is thrown The program call stack “unwinds” Stack frame for each function up call chain is popped Stack variables in each popped frame are destroyed Until an enclosing try/catch scope is reached where the type of exception thrown is caught. Control passes to first matching catch block Can handle the exception and continue Can free resources and re-throw CAMP 06: Maturing Minds
More on “try” and “catch” Whenever a function is called in a try block, the “catch” blocks to be examined after the try block are known as the extended prototype of a function includes the throw clauses. catch blocks after a try block are examined in order when an exception is thrown from a function called in the try block. Parentheses for each catch block has semantics of a “function argument declaration” CAMP 06: Maturing Minds
Exception Specifications Make promises to the caller Allow stronger type checking enforced by the compiler By default, a function can throw anything it wants A throw clause in the signature Limits what a function can throw A promise to the calling function A throw clause with no types Promises nothing will be thrown Can list multiple types Comma separated // can throw anything void Calculator::subtract (int i); // promises not to throw Calculator::add (int i) throw (); // promises to only throw int Calculator::divide (int i) throw (int); CAMP 06: Maturing Minds
previous frame pointer Stack Frame g++ -s gives assembler output that can be used to deduce exact structure for a given platform In general, the overall structure is common A chunk of memory representing a function call Pushed on program call stack at run-time Contains: The frame pointer The return address for the call (i.e., where it was called from) Parameters passed to the function Automatic (stack) variables for the function automatic variables parameters previous frame pointer return address CAMP 06: Maturing Minds
Illustrating the Call Stack Stack frame for function main Pushed on program call stack With stack variables i and c With parameters argc and argv Note that parameters are initialized at frame creation Variables are not necessarily initialized at frame creation May occur later in called function int main (int argc, char **argv) { int i = 0; Calculator c; try c.divide (0); cout << c.get_value (); } catch (int) return 1; return 0; i c value_ main argc argv CAMP 06: Maturing Minds
Illustrating the Call Stack, cont. int main (int argc, char **argv) { int i = 0; Calculator c; try c.divide (0); cout << c.get_value (); } catch (int) return 1; return 0; Enter function main Stack variable initialized to 0 i c value_ main argc argv CAMP 06: Maturing Minds
Illustrating the Call Stack, cont. int main (int argc, char **argv) { int i = 0; Calculator c; try c.divide (0); cout << c.get_value (); } catch (int) return 1; return 0; Call Default Constructor for c Push a new stack frame No parameters or automatic variables for that specific function Params depend on function signature declaration Automatics depend on function body definition Calculator:: Calculator ( ) this i c value_ main argc argv CAMP 06: Maturing Minds
Illustrating the Call Stack, cont. Calculator::Calculator () : value_ (0) {} void Calculator::divide (int i) throw (int) { if (i == 0) { throw i; } else { value_ /= i; } cout << value_; Enter function Calculator::Calculator ( ) Member variable value_ of stack variable c is initialized to zero How do we know which value_ to set? There may be multiple Calculator instances Answer: implicit “this” parameter in stack frame Calculator:: Calculator ( ) this i c value_ main argc argv CAMP 06: Maturing Minds
Illustrating the Call Stack, cont. Calculator::Calculator () : value_ (0) { } void Calculator::divide (int i) throw (int) if (i == 0) { throw i; } else { value_ /= i; cout << value_; Return from function Calculator::Calculator ( ) Pop the stack frame, return to previous argc argv i c value_ main CAMP 06: Maturing Minds
Illustrating the Call Stack, cont. int main (int argc, char **argv) { int i = 0; Calculator c; try c.divide (0); cout << c.get_value (); } catch (int) return 1; return 0; Call divide method on c Push a new stack frame Contains parameters this and i Copy address of current instance into this Copy value 0 into i void Calculator:: divide (int ) main argc argv i c value_ this CAMP 06: Maturing Minds
Illustrating the Call Stack, cont. Calculator::Calculator () : value_ (0) { } void Calculator::divide (int i) throw (int) if (i == 0) { throw i; } else { value_ /= i; cout << value_; Enter function Calculator::divide (int) Test i equal to 0 and take the true branch Throw integer i main void Calculator:: Calculator (int ) argc argv i c value_ this CAMP 06: Maturing Minds
Illustrating the Call Stack, cont. Calculator::Calculator () : value_ (0) { } void Calculator::divide (int i) throw (int) if (i == 0) { throw i; } else { value_ /= i; cout << value_; Thrown exception unwinds call stack Notice control skips over cout statement to end Pop the stack frame, return to previous Return from function void Calculator::divide ( ) argc argv i c value_ main CAMP 06: Maturing Minds
Illustrating the Call Stack, cont. int main (int argc, char **argv) { int i = 0; Calculator c; try c.divide (0); cout << c.get_value (); } catch (int) return 1; return 0; We’ve reached an enclosing try/catch scope So stack unwinding stops Control jumps to first matching catch block Again, skips over intervening cout statement argc argv i c value_ main CAMP 06: Maturing Minds
More on catch Control jumps to first matching catch block try { // can throw an exception } catch (Derived &d) // ... catch (Base &b) catch (...) // catch all... Control jumps to first matching catch block Order matters with multiple possible matches Especially with inheritance-related exception classes Hint: put catch blocks for derived exception classes before catch blocks for their respective base classes More specific catch before more general catch catch (…) catches any type CAMP 06: Maturing Minds
A Few More on catch Notice catch-by-reference for user defined types try { // can throw an exception } catch (MyClass &e) // ... throw; // rethrows e catch (int) catch (...) // catch all... Notice catch-by-reference for user defined types More efficient Only a reference propagates Rather than entire object More correct Avoids class-slicing problem if catch as base type, rethrow Preserves polymorphism More on this in later lectures Can leave off variable name Unless catch block needs to do something with the instance that was caught CAMP 06: Maturing Minds
Interra Induction Training Object Oriented Programming in C++ Templates Kolkata, July 25, 2005
What is a Template? Templates are specifications of a collection of functions or classes which are parameterized by types. Examples: Function search, min etc.. The basic algorithms in these functions are the same independent of types. But, we need to write different versions of these functions for strong type checking in C++. Classes list, queue etc. The data members and the methods are almost the same for list of numbers, list of objects. We need to define different classes, however. CAMP 06: Maturing Minds
Function Template: An Example void swap(int &i, int &j) { int temp; temp = i; i = j; j = temp; } void swap(String &i, String &j) String temp; template<class X> void swap (X &one, X &other) { X temp; temp = one; one = other; other = temp; } Main() { int I=10, j=20; swap(I, j); String s1(“abc”), s2(“def”); swap(s1, s2); Type parameter Type parameter list Template instantiation CAMP 06: Maturing Minds
Parameterized Functions A function template describes how a function should be built supplies the definition of the function using some arbitrary types, (as place holders), a parameterized definition can be considered the definition for a set of overloaded versions of a function is identified by the keyword template followed by parameter identifiers enclosed between < and > delimiters noting they are class, (i.e. type), parameters CAMP 06: Maturing Minds
Template Non-type Parameter It is an ordinary parameter template <class T, int size> T min (T (&x[size])); When min is called, size is replaced with a constant value known at compile time The actual value for a non-type parameter must be a constant expression. CAMP 06: Maturing Minds
typename The key words class and typename have almost the same meaning in a template parameter. typename is also used to tell the compiler that an expression is a type expression. template <class T> f (T x) { T::name * p; // Is this a pointer declaration or multiplication? } typename T::name * p; // Is this a pointer declaration or multiplication? CAMP 06: Maturing Minds
Template Argument Deduction Each item in the template parameter list is a template argument. When a template function is invoked, the values of the template arguments are determined by seeing the types of the function arguments. Template <class T, int size> Type min( T(&x[size])); Int pval[9]; min(pval); //Error!! Three kinds of conversions are allowed. L-value transformation (e.g., Array-to-pointer conversion) Qualification conversion Conversion to a base class instantiation from a class template If the same template parameter are found for more than one function argument, template argument deduction from each function argument must be the same. CAMP 06: Maturing Minds
Explicit Template Arguments It is possible to override template argument deduction mechanism and explicitly specify the template arguments to be used. template <class T> T min(T x, T y); unsigned int ui; min (ui, 1024); //Error!! min<unsigned int>(ui, 1024); // OK Specifying return type generically is often a problem. template <class T, class U> ??? sum(T x, U y); sum(ch, ui) returns U; sum (ui, ch) returns T template < class R, class T, class U> R sum(T x, U y) min<int>(i, ‘a’); CAMP 06: Maturing Minds
Template Explicit Specialization Some times, a template may not be suitable for all types. The following template is not good for char * template <class T> T min(T x, T y) { return (x < y ? x : y); } Define the function explicitly for char * template<> char * min <chr *>(char *x, char *y) { return (strcmp(x, y) < 0 ? x : y); } CAMP 06: Maturing Minds
Class Template
A List Template Class CAMP 06: Maturing Minds template<class T> class List { public : List (); virtual ~List (); int put (const T &val); T *unput (); T *get (); int unget (const T &val); T *find(const T &val); int length (); private: struct Node { Node *next_item; T *list_item; } *beg_ptr; *end_ptr; int how_many; }; template<class T> int List<T>:: put (const T &val) { Node *tmp_ptr = new Node; if (tmp_ptr && (tmp_ptr->list_item = new T (val) ) ) { tmp_ptr->next_item = 0; if (end_ptr) end_ptr->next_item = tmp_ptr; else beg_ptr = tmp_ptr; end_ptr = tmp_ptr; how_many++; return 1; } return 0; CAMP 06: Maturing Minds
Using a Template Class int main () { register int i, *iptr; String *sptr; char *somedata [] = {“one”, “two”, “three”, “four”, “five”, “six”, “seven”, “eight”, “nine”, “ten”}; List<int> ii; List<String> is; for (i = 1; i <=10; i++) { ii.put(i); } } cout << “The List<int> contains “ ; cout << ii.length () << “ items\n” ; return 0; } CAMP 06: Maturing Minds
Parameterized Class A class template describes how a class should be built Supplies the class description and the definition of the member functions using some arbitrary type name, (as a place holder). is a parameterized type with parameterized member functions can be considered the definition for an unbounded set of class types is identified by the keyword template followed by parameter identifiers enclosed between < and > delimiters noting they are class, (i.e. type), parameters is often used for “container” classes CAMP 06: Maturing Minds
Parameter Requirements Parameter Types may be of any type, (including user defined types) may be parameterized types, (i.e. templates) MUST support the methods used by the template functions: what are the required constructors ? the required operator functions ? What are the necessary defining operations ? CAMP 06: Maturing Minds
Class Template Instantiation Class Template is instantiated only when it is required. Matrix is a class template Matrix m; //error Matrix *pm; // OK void inverse (Matrix & m); //OK Class template is instantiated before An object is defined with class template instantiation If a pointer or a reference is de-referenced (e.g., a method is invoked) A template definition can refer to a class template or its instances but a n non-template can only refer to template instances. CAMP 06: Maturing Minds
Friend & Static Declaration There are 3 kinds of friend declarations Non-template friend. A bound friend class template. One-to-one mapping between the instance of a class template and its friend An unbound friend class template. One-to-many mapping between the instance of a class template and its friend Operators can be overloaded for a class template A static data member in a class template is itself a template. Each static data member instantiation corresponds to a class template instantiation. CAMP 06: Maturing Minds
Source code organization Inclusion Model Make the template definition visible to compiler at the point of instantiation Include source files as well. Increase in build and link time Instantiate the types you need explicitly in a separate compile unit. Cannot use benefits of lazy instantiation. Separation Model Use keyword ‘export’ in front of definition. Not many compiler supports the feature. CAMP 06: Maturing Minds
Template specialization Allows to make specific implementation when pattern is of determined type. The syntax is template<> class XXX<Type> {..} No member is ‘inherited’ from the generic template to specialized one. So, must define ALL members equating them to specialization Class templates can be partially specialized too. A totally disjoint template that the compiler gives a priority while instantiation. CAMP 06: Maturing Minds
Templates & Derivation A template expresses a commonality across types Two types generated from a common template are different. A Base class expresses commonality of representation and calling interface. Example template <class T, class A> class specalContainer : public Container<T>, A; specialContainer<Node, Fast_Allocator> s; specialContainer<Node, Shared> s1; specialContainer<ProcessDescriptor, Fast_Allocator> p; CAMP 06: Maturing Minds
Template Inheritance: A Base Template template<class T> class set { public : Set ( ) { } ; virtual void add (const T &val); int length ( ) ; int find (const T &val); private: List<T> items; }; template<class T> void Set<T> : : add (const T &val) { if (items.find (val) ) return; items.put (val) ; } int Set<T> : : length ( ) return items.length ( ) ; int Set<T> ::find (const T &val) return (int) items.find(val); CAMP 06: Maturing Minds
Template Inheritance: A Derived Template /* boundset.h */ #include “set.h” template<class T> class BoundSet : public Set<T> public: BoundSet (const T &lower, const T &upper); void add(const T &val); private: T min; T max; }; template<class T> BoundSet<T>:: BoundSet (const T &lower, const T &upper) : min (lower), max (upper) { } void BoundSet<T> : :add(const T &val) if (find (val) ) return; if ( (val <= max) && (val >= min) ) Set<T>: : add (val) ; CAMP 06: Maturing Minds
Using a Derived Template Class int main ( ) { register int i ; BoundSet<int> bsi (3, 21); Set<int> *Setptr = &bsi; for (i = 0; i < 25; i++) setptr->add( i ) ; if (bsi.find (4) cout << “We found an expected value\n”; if (bsi.find (0) || bsi.find(25 ) ) { cout << “We found an Unexpected value\n”; return 23; } else cout << “We found NO unexpected value\n”; return 0; CAMP 06: Maturing Minds
Inheritance vs Templates Inheritance : helps in reusing object code Templates : helps in reusing source-code object code size of template code is therefore much less. Compiler view Constructor of objects containing virtual functions must initialize the vptr table. Template class knows the type of the class at compile-time instead of having to determine it at run-time (as in case of virtual function usage) CAMP 06: Maturing Minds
Inheritance vs Templates: Example Implement the following command. # ECHO infile outfile main() { (argc > 2 ? ofstream (argv[2] ,ios::out) : cout) << (argc > 1 ? ifstream (argv[1], ios::in) : cin) .rdbuf(); } main() { fstream in, out; if (argc > 1) in.open(argv[1], ios::in); if (argc > 2) out.open(argv[2], ios::out); Process(in.is_open() ? in : cin, out.is_open() ? out : cout); } How to implement ‘Process’ ? Two ways to get the polymorphic behavior virtual function and templates CAMP 06: Maturing Minds
Inheritance vs Templates: Solution template<typename In, typename out> void process(In& in, Out& out) { // out << in.rdbuf(); } Merely requires that the passed objects to have suitable interface (such as member function named rdbuf(). ) void Process (basic_istream& in, basic_ostream& out) { // out << in.rdbuf(); } Requirement: cin and ifstream both derived from basic_istream The common base class ‘basic_istream has suitable interface ‘rdbuf’. Both Methods solve the current problem. But templates provide extensibility. Other streams can be provided with rdbuf() interface. Other streams cannot be guaranteed to be derived from the same base class CAMP 06: Maturing Minds
Another Example A collection of classes is required for Stack: for ints , strings, floats etc. Has operations: push, pop, length of stack. transportationMode . For airplane, car, boat etc. Has features : move, comfort etc each move in diff ways. Each provide different level of comfort. Analyze if the ‘type’ being manipulated has any affect on the behavior of class . If ‘type’ does not affect the behavior, use templates If ‘type’ affects the behavior, use virtual functions (inheritance) CAMP 06: Maturing Minds