Download presentation
Presentation is loading. Please wait.
Published byCarol Barber Modified over 9 years ago
1
Object Oriented Programming Lect. Dr. Daniel POP Universitatea de Vest din Timişoara Facultatea de Matematică şi Informatică
2
2Programming IIObject-Oriented Programming Course #9 Agenda Generic Programming (continued) Using template arguments to specify policy Derivation and templates Run-time type information (RTTI) Introduction Dynamic casting Static casting vs. dynamic casting Typeid and extended type information Uses and misuses of RTTI
3
3Programming IIObject-Oriented Programming Using template arguments to specify policy (I) DEFINITION [Policy] = a definite course or method of action selected from among alternatives and in light of given conditions to guide and determine present and future decisions. [Webster dictionary] Example: method to compare elements of a vector in a sorting algorithm; different criteria can be used for the same type: case/non-case sensitive, for English/Romanian etc. template int compare(const String & s1, const String & s2) { for(int i=0; i<s1.length() && i<s2.length(); i++) if(!C::eq(s1[i], s2[i])) return C::lt(s1[i], s2[i]) ? -1 : 1; return s1.length()-s2.length(); } void f(String str1, String str2) { compare >(str1, str2); compare (str1, str2); } template class Cmp { public: static int eq(T a, T b) { return a==b; } static int lt(T a, T b) { return a<b; } } class NoCase { public: static int eq(char a, char b) { return ???; } static int lt(char a, char b) { return ???; } }
4
4Programming IIObject-Oriented Programming Using template arguments to specify policy (II) Benefits of passing policies as template arguments over passing pointers to functions: ― several operations can be passed a single argument with no run-time cost ― easier to inline while inlining a call through a pointer to a function requires special attention from compiler. template > int compare(const String & s1, const String & s2) { // …. } void f(String str1, String str2) { compare(str1, str2); } Default template parameters
5
5Programming IIObject-Oriented Programming Derivation and templates (I) Both are mechanisms to build new types from existing ones Deriving a template from a non-template class (see Course 8 / ex. list) provides a common implementation for a set of templates; in other words, template provides a safe interface to a non-safe type Passing the derived type to base class => definition of the basic operations on containers only once and separate from the container definition itself. Examples: template class BasicOp { bool operator==(const C&) const; bool operator!=(const C&) const; }; // passing the derived type to base class template class MathContiner : public BasicOp > { public: T& operator[](size_t); }; // template class derivation template class vector { }; template class V : public vector { }; template bool BasicOp ::operator== (const C& a) const { if(size()!=a.size()) return false; // …. }
6
6Programming IIObject-Oriented Programming Derivation and templates (II) Alternative way to keep containers and operations separate: use template arguments template class Mcontainer { private: C elements; public: T& operator[](size_t) {return elements[i]; } friend bool operator==(const Mcontainer&, const Mcontainer&); }; Mcontainer > mc; Parametrization vs. inheritance two techniques to implement polymorphic behaviour run-time polymorphism – usage of virtual functions and inheritance compile-time (parametric) polymorphism – usage of templates When choose one or another approach? If hierarchical relationship exist between types use run-time polymorphism; otherwise use templates; if run-time efficiency is a must, use templates
7
7Programming IIObject-Oriented Programming Member templates A class (or a template class) can have members that are themselves templates. Example: template class complex { private: S re, im; public: template complex(const complex & c) : re(c.re), im(c.im) { } }; void f() { complex cf; complex cd = cf; // use float -> double conv. class Quad { } ; // without conversion to int complex cq; complex ci = cq; // error: no conv. Quad -> int exist } Usage of checked_cast operator to avoid unreasonable conversions. Illegal to have virtual and template: template virtual bool intersect();
8
8Programming IIObject-Oriented Programming Inheritance relationship Let’s say that Shape is a base class of Circle. Treating set as set is a serious logic error. Example: void f(set & s) { s.add(new Triangle()); } void g(set & c) { f(c); // error: no set to set conversion }
9
9Programming IIObject-Oriented Programming Template conversion Use member templates to specify relationships between templates when necessary Example: template class Ptr { T* p; Public: Ptr(T*); // convert Ptr to Ptr template operator Ptr (); }; template template Ptr ::operator Ptr () { return Ptr (p); // T2* has to be a T* } void f(Ptr pc) { Ptr ps = pc; // ok: Circle* is a Shape* Ptr p2 = ps; // error: Shape* isn’t a Circle* }
10
10Programming IIObject-Oriented Programming Run-time type information (RTTI) Introduction Dynamic casting Static casting vs. dynamic casting Typeid and extended type information Uses and misuses of RTTI
11
11Programming IIObject-Oriented Programming Introduction DEFINITION [RTTI] The use of type information at run-time is referred as “run-time type information” (RTTI). DEFINITION [upcast, downcast, crosscast] Casting from base to derived class is called downcast. Casting from derived to base is called upcast. Casting from a base to a sibling base is called crosscast. Recover the “lost” type of an object Example: EmployeeManagerTemporaryConsultant voif f(Temporary* pt) { // crosscast Employee* pe = dynamic_cast (pt); if(pe) pe->print(); }
12
12Programming IIObject-Oriented Programming Dynamic casting Syntax: class C : public A, private B { }; void f(C* pc) { B* pb1 = pc; // error: B is a private base B* pb2 = dynamic_cast (pc); // => NULL } dynamic_cast (p) where, T – a type, p – a pointer or reference Usage for upcast not necessary doesn’t allow the violation of protection of private and protected base classes. Usage for downcasting or crosscasting, where correctness cannot be solved at compile-time if the object pointed by p is not NULL and is of class T or has a unique base class of type T, then dynamic_cast returns a pointer of type T* of that type; othewise returns 0 the type of pointer p has to be a polymorphic type, otherwise 0 is returned. T- doesn’t have to be polymorphic always test the result against 0 value!
13
13Programming IIObject-Oriented Programming Implementation of dynamic_cast If RTTI is enabled, then a pointer to type information object (tye_info) is stored in the VFT (Virtual Function Table) attached to a polymorphic type type_info object contains the list of base classes dynamic_cast simply compares the type_info objects representing the base classes
14
14Programming IIObject-Oriented Programming Dynamic casting and references If p is pointer then an error is signaled with a NULL (0) value. This is not feasible if p is a reference! A bad_cast exception is thrown. voif f(Temporary& rt) { try { Employee& re = dynamic_cast (rt); re.print(); } catch(bad_cast) { // … }
15
15Programming IIObject-Oriented Programming Dynamic casting and multiple inheritance Multiple inheritance: pay attention to base classes that appears more than once in a diamond- like inheritance. Example: class Storable { } ; class Component : public virtual Storable { }; class Receiver : public Component { }; class Transmitter : public Component { }; class Radio : public Receiver, public Transmitter { }; void f(Radio& r) { Storable* ps = &r; Component* pc = dynamic_cast (ps); // => 0; which Component? of Receiver or Transmitter? }
16
16Programming IIObject-Oriented Programming Static casting vs. dynamic casting static_cast does not examine the object it cast from, while dynamic_cast does! static_cast does not require a polymorphic object. static_cast does not make any checking; dynamic_cast checks the cast to be valid. dynamic_cast can cast from a polymorphic virtual base to derived / sibling class, but static_cast cannot do this because it doesn’t examine the object it cast from. void f(Radio& r) { Receiver* pr = &r; // ok Radio* pradio = static_cast (pr); // ok, unchecked pradio = dynamic_cast (pr); // ok, checked at run-time Storable* ps = &r; // Storable is virtual base of Radio pradio = static_cast (ps); // error: cannot cast from virtual base pradio = dynamic_cast (ps); // ok, run-time checked } void g(void* p) { Radio* pr = static_cast (p); // trust the programmer pr = dynamic_cast (p); // error: void is not polymorphic => dynamic_cast can’t be used to cast from void* }
17
17Programming IIObject-Oriented Programming Remarks Both, static & dynamic casts respect const and access controls. Examples: class C : public A, private B { }; void f(C* pc, const A* pa) { B* pb1 = pc; // error: B is a private base B* pb2 = dynamic_cast (pc); // => NULL B* pb3 = static_cast (pc); // error static_cast (a); // error: can’t cast away const dynamic_cast (a); // error: can’t cast away const A* ppa = const_cast (a); // OK } Calling virtual functions or accessing run-time type information from constructors is not wise because the object is not completely constructed at that point and its real/final type is not yet known.
18
18Programming IIObject-Oriented Programming Typeid Sometimes is important to know the exact type of an object (class name) typeid operator serves this scope by returning an object representing the type of its operand, i.e. a const reference to a type_info. if the operand is NULL it throws a bad_typeid exception. type_info class exposes the following interface: operator== and operator!= – allows comparision of types; name() – returns the name of the type; before(type_info&) – allow to sort type_info Usually, there are more than one instance of type_info objects for a single class (type)! The character representation of the type name is implementation-dependent. Example: void f(Shape* ps, Shape& rs) { cout << “Shape type is: ” << typeid(rs).name(); if(typeid(*ps) == typeid(rs)) cout << “The same type.”; }
19
19Programming IIObject-Oriented Programming Extended type information Use maps to store extended information about types. Example: map layoutTable; hash_map iconTable; void f(Base* p) { Layout& l = layoutTable[typeid(*p).name()]; // use l Icon& icon = iconTable[&typeid(*p)]; // use icon }
20
20Programming IIObject-Oriented Programming Misuses of RTTI void f(Shape* ps) { if(typeid(*ps) == typeid(Circle)) // actions for Circle else if(typeid(*ps) == typeid(Triangle)) // actions for Triangle // etc. } Don’t abuse of type information; rely on polymorphism implemented using virtual functions whenever possible! NOT THIS WAY!! class Object { }; class Container : public Object { public: void put(Object *); Object* get(int idx); }; class My : public Object { } ; My f(My* p, Container* c) { c->put(p); Object* po = c->get(12); if( My* p1 = dynamic_cast (po) ) return p1; } NOT THIS WAY!! HOMEWORK: Re-write these two examples in a more suitable form!
21
21Programming IIObject-Oriented Programming Uses of RTTI Extend class functionality without changing existing class because either is not accessible (for example, a class from an external library) or changing the class implies a lot of changes in other classes as well (for example, adding dummy functions). Implementation of a simple I/O system. void read_file(istream& is) { IOobject* p = getObject(is); if( Shape* shape = dynamic_cast (p) ) { shape->draw(); } else if( Layout* layout = dynamic_cast (p)) { canvas->setLayout(layout); } else cout << “Invalid object found in file.”; }
22
22Programming IIObject-Oriented Programming Further Reading [Stroustrup, 1997] Bjarne Stroustrup – The C++ Programming Language 3rd Edition, Addison Wesley, 1997 [Chapter 13, 15.4][Stroustrup, 1997] Bjarne Stroustrup – The C++ Programming Language 3rd Edition, Addison Wesley, 1997 [Chapter 13, 15.4]
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.