Inheritance Inheritance The main ideas are similar to
- Slides: 124
Inheritance
Inheritance • The main ideas are similar to what you already know from Java • C++ has no interfaces but it allows multiple inheritance • We will discuss later the problems that arise: Class A Class B Class C Class D 2
Inheritance • The main ideas are similar to what you already know from Java • Inheritance should be used for “is-a” and not for code-reuse (in this case, composition should be preferred) • Inheritance lets you use runtime polymorphism – List of pointer to Shapes where some are Circle, some are Rectangle… 3
Person class Person { private: std: : string _name; int _id; static constexpr int NO_ID_VAL= -1; public: Person (const std: : string& name, int id); void change. Name(const string& name); void change. Id(int id); std: : string get. Name() const; int get. Id() const; } ; 4
protected • Class members that should be accessible by subclasses only are declared as protected. 5
protected • To allow class Programmer to access the members of class Person, we would define: class Person { protected: std: : string _name; int _id; static constexpr int NO_ID_VAL= -1; public: . . . 6
Programmer class Base class #include "Person. hpp" class Programmer : public Person { Derived class std: : string _company; public: Programmer(const std: : string& name, int id, const std: : string& company); … ; 7
Programmer class implementation #include "Programmer. hpp" Programmer: : Programmer (const std: : string& name, int id, const std: : string& company) : Person(name, id), _company(company) { // EMPTY Considered elegant } 8
Objects of Programmer can use Person’s methods int main() { Programmer yoram("Yoram", 1226611, "N. G. C ltd. "); cout << yoram. get. Company() << endl; yoram. change. Company("Microsoft"); cout << yoram. get. Name() << " " << yoram. get. Id() << endl; yoram. change. Name("Yori"); yoram. change. Id(2266110); . . . } 9
Functions you don’t inherit: • Ctors, Dtors (may be called automatically) • Operator= (may be called automatically) 10
public, protected and private inheritance
public, protected and private inheritance A base class also has an access modifier: class Programmer : public Person or class Programmer : protected Person or class Programmer : private Person Private inheritance: • Inside Programmer you can access Person public members • Objects of Programmer do not have Person members 12
public, protected and private inheritance A base class also has an access modifier: class Programmer : public Person or class Programmer : protected Person or class Programmer : private Person Default for structs Default for classes Private inheritance: • Inside Programmer you can access Person public members • Objects of Programmer do not have Person members 13
public, protected and private inheritance class Base {…}; class Public. Derived : public Base{…}; class Protected. Derived : protected Base{…}; class Private. Derived : private Base{…}; Access rules: (1) No access to Base private section from derived classes (2) Public. Derived inherits public Base members as public, and protected members as protected (3) Protected. Derived inherits public and protected Base members as protected (4) Private. Derived inherits public and protected Base members as private 14
public inheritance – regular Is-A 15
private inheritance – can, but often shouldn’t, be used as a replacement for composition (code reuse, implementation) Prefer composition! 16
private/protected are in class level and not in instance level class A { private: int _i; public: A(int i) : _i(i) {} void set. Ifrom. A(A a) { _i = a. _i; ok } }; 17 int main () { A a(5); A b(2); b. set. Ifrom. A(a); }
C-tor & D-tor order of execution
C-tor & D-tor order of execution 1. Constructor of the base class is executed 2. Constructor of the class itself is executed Destruction is done in the opposite order 19
C-tor & D-tor order of execution 1. Constructor of the base class is executed 1. First members in initialization list 2. Then body 2. Constructor of the class itself is executed 1. First members in initialization list 2. Then body Destruction is done in the opposite order 20
C-tor & D-tor order of execution class A { int _a; public: A(int a) : _a(a) { cout << "A ctorn"; } ~A() { cout << "A dtorn"; } }; class B : public A { int _b; public: B(int a, int b) : A(a), _b(b) { cout << “B ctorn"; } ~B() { cout << “B dtorn“; } };
C-tor & D-tor order of execution int main() { B b(1, 2); } What will be the output?
C-tor & D-tor order of execution int main() { B b(1, 2); } What will be the output? A ctor B dtor A B
Overriding
Person class Person { . . . void output. Details(std: : ostream& os) const; . . . } ; 25
Programmer class – Override #include "Person. hpp" class Programmer : public Person { . . . void output. Details(std: : ostream& os) const; . . . }; 26
Overridden member functions void Person: : output. Details(std: : ostream& os) const { os << "{"; if(_name != "") os << " name: " << _name; if(_id != NO_ID_VAL) os << " ID: " << _id; os << '}'; } void Programmer: : output. Details(std: : ostream& os) const { Person: : output. Details(os); 27 os << '-' << _company << '}'; }
Default Operator= not inherited but the default one uses the father’s automatically 28
Explicit Operator= Person& Person: : operator=(const Person& other) { . . . return *this; } Programmer& Programmer: : operator=(const Programmer& other) { Person: : operator=(other); . . . 29 return *this; }
Virtual Classes & Polymorphism
Example (revisited) • We want to implement a graphics system • We plan to have lists of shape. Each shape should be able to draw itself, compute its size, etc. 31
Solution #1 class Shape { public: enum Type { Square, Circle, Triangle }; Shape( Type t, const Point& Center, double width, double height); void draw() const; double area() const; private: Type _type; Point _center; }; 32
Solution #1 This solution gives a nice “wrapping” to the solution we consider in C It does not solve the problems of that solution �Lack of extendibility 33
Solution #2 – different classes class Square { public: void draw() const; double area() const; }; 34 class Circle { public: void draw() const; double area() const; };
Solution #2 – Discussion �Each shape has its own implementation �We can easily add new shapes However, �Shapes are different types �One cannot view them as part of the same class - we cannot share code between them 35
Solution #3 – hierarchy class Shape { public: void draw() const {cout<<'h'; } double area() const; }; class Square: public Shape { public: void draw() const {cout<<'q'; } 36 double area() const; }; class Circle: public Shape { public: void draw() const; {cout<<'c'; } double area() const; };
Solution #3 Now if we write Shape my. Shapes[2]; my. Shapes[0] = Circle(); my. Shapes[1] = Square(); What will happen? 37
Solution #3 Now if we write Shape my. Shapes[2]; my. Shapes[0] = Circle(); my. Shapes[1] = Square(); What will happen? The Circle and Square will be constructed and then sliced to fit inside the Shape objects 38
Solution #3 Now if we write (like in Java): Shape* my. Shapes[2]; my. Shapes[0] = new Circle(); my. Shapes[1] = new Square(); What will happen when we call my. Shapes[0]->draw(); ? 39
Solution #3 Now if we write (like in Java): Shape* my. Shapes[2]; my. Shapes[0] = new Circle(); my. Shapes[1] = new Square(); What will happen when we call my. Shapes[0]->draw(); ? h will be printed! 40
Why? When we write: Circle circle; circle. draw(); The compiler calls Circle: : draw() When we write: Shape* p = new Circle(); p->draw(); The compiler calls Shape: : draw() Why? *p has type Shape 41
Static resolution (aka early/static binding/resolution) 42
Static resolution How does the compiler determine which method to call? Static Resolution: Based on the type of the variable. �Not the type of the object! The compiler finds the most specific implementation of the method, and calls it 43
Static resolution in our example Circle* circle = new Circle(1, 1, 2); Square* square = new Square(2, 2, 1); Shape* my. Shapes[2]; my. Shapes[0] = circle; my. Shapes[1] = square; circle->draw(); // Calls Circle: : Draw() square->draw(); // Calls Square: : Draw() my. Shapes[0]->draw(); // Calls Shape: : Draw() my. Shapes[1]->draw(); // Calls Shape: : Draw() 44
Underneath the Hood: Inheritance class Base { double _x; int _a; }; class Derived : public Base { double _z; }; 45 Base a; Derived b;
Underneath the Hood: Inheritance class Base { double _x; int _a; }; class Derived : public Base { double _z; }; Base a; Derived b; a: _x _a b: _x _a _z 46 Base
Pointing to an Inherited Class Derived b; Base* p = &b; p: When using *p, we treat b as though it was a Base object The compiler cannot know if *p is from a derived class or not 47 b: _x _a _z
Dynamic Resolution (aka late/dynamic binding/resolution) 48
Dynamic Resolution Static resolution is clearly not what we want to in this example More desirable here is – Dynamic resolution: • Based on the type of the object • Determined at run time [Java Like] 49
Dynamic Resolution in C++ The virtual keyword states that the method can be overridden in a dynamic manner. class Base { public: virtual void bar(); } class Derived: public Base { public: virtual void bar(); } 50
dynamic resolution Returning to the shapes example, using virtual methods gives the desired result 51
dynamic resolution class Shape class Circle: public Shape { { public: virtual void draw() const {cout<<'h'; } {cout<<'c'; } virtual double area() const; }; class Square: public Shape { public: virtual void draw() const {cout<<'q'; } virtual double area() const; }; 52
dynamic resolution Returning to the shapes example, using virtual methods gives the desired result: Shape* s=new Circle; s->draw(); Will print 'c' 53
Virtual Methods Class Base defines a virtual method foo() The resolution of foo() is dynamic in all subclasses of Base �If the subclass Derived overrides foo(), then Derived: : foo() is called �If not, Base: : foo() is called 54
With references struct B { virtual void f() { cout << "B" << endl; } }; struct D : public B { virtual void f() { cout << "D" << endl; } }; 55 int main() { D d; B b= d; b. f(); //B B& bref= d; bref. f(); //D }
Base function that calls virtual function struct B{ virtual void f() { cout<< "Base f()" <<endl; } void g() { f(); } }; struct D : public B { virtual void f() { cout<< “Derived f()" <<endl; } }; int main(){ D d; d. g() will print “Derived f()”. Why? ? 56
Base function that calls virtual function struct B{ virtual void f() { cout<< "Base f()" <<endl; } void g(B* this) {this->f(); } }; struct D : public B { virtual void f() { cout<< “Derived f()" <<endl; } }; int main(){ D d; B: : g(&d) will print “Derived f()”. Why? ? 57
Calling virtual function from a constructor struct B { B() { f(); } virtual void f(){ cout<<“Base f()”<<endl; } }; struct D : public B { virtual void f(){ cout<<“Derived f()”<<endl; } }; int main(){ D d; // would print “Base f()” Conclusion: Do not call virtual functions from a constructor! 58
Calling virtual function from a destructor struct B { ~B() { f(); } virtual void f(){ cout<<“Base f()”<<endl; } }; struct D : public B { virtual void f(){ cout<<“Derived f()”<<endl; } }; int main(){ D d; // would print “Base f()” Conclusion: Do not call virtual functions from a destructor! 59
Polymorphism rules: When calling a method, polymorphism will take place if: � We call a method through pointer or reference to a base class that actually points to a derived object. � The method must be virtual. � The derived class must override the base method with exactly the same signature (C++11 use override to check that the method really overrides in compile time) 60
Implementation of Virtual Methods (under the hood) 61
Implementation of Virtual Methods Possible approach: �If foo() is a virtual method, then each object has a pointer to the implementation of foo() that it uses �Can be implemented by using array of pointers to functions Cost: �Each virtual method requires a pointer �Large number of virtual methods � waste of memory 62
Implementation of Virtual Methods Alternative solution: �Each object has a single pointer to an array of function pointers �This array points to the appropriate functions Cost: �For each class, we store one table �Each object contains one field that points to the right table 63
class A { public: virtual void f 1(); virtual void f 2(); int _a; }; class B: public A *a 1: { public: virtual void f 1(); virtual void f 3(); *a 2: void f 4(); int _b; }; *a 3: A* a 1= new A; A* a 2= new A; A* a 3= new B; 64 void A: : f 1 { //. . . }; <vptr> _a _b VTBLs A f 1 f 2 B f 1 f 2 f 3 void A: : f 2 { //. . . }; void B: : f 1 { //. . . }; void B: : f 3 { //. . . };
Through *a 3 everything below the class A { red dashed line will be hidden public: virtual void f 1(); (you can downcast to a different virtual void f 2(); name, later) int _a; }; class B: public A *a 1: { public: virtual void f 1(); virtual void f 3(); *a 2: void f 4(); int _b; }; *a 3: A* a 1= new A; A* a 2= new A; A* a 3= new B; 65 <vptr> _a _b VTBLs A f 1 f 2 B f 1 f 2 f 3 void A: : f 1 { //. . . }; void A: : f 2 { //. . . }; void B: : f 1 { //. . . }; void B: : f 3 { //. . . };
Calling virtual function from a ctor/dtor explained �When the code to the ctor/dtor is generated its generated to its class and not for a different class �Thus, the vptr will be to the vtable of the same class 66
Virtual - Recap �Virtual controls whether to use static or dynamic resolution �Once a method is virtual, it must remain so throughout the hierarchy �Works only with pointers or references �Calling a virtual method is more expensive than standard calls �Two pointers are “chased” to get to the address of the function �No inlining 67
Destructors & Inheritance 68
Destructors & Inheritance class Base { public: ~Base(); }; class Derived : public Base { public: ~Derived(); }; Base *p = new Derived; delete p; Which destructor is called? (Base: : ~Base()) 69
Virtual Destructor • Destructor is like any other method • The example uses static resolution, and hence the wrong destructor is called • To fix that, we need to declare virtual destructor at the base class! Once you declare virtual destructor, derived class must declare a destructor 70
Polymorphism & Inheritance - recap 71
Polymorphism & Inheritance - recap • C++ allows to use class hierarchy to implement polymorphic code Points of care: • Choice of virtual methods �Run time considerations • Use of virtual destructor for base class 72
Example Revisiting our example, we write: class Shape { public: virtual ~Shape(); virtual void draw() const; virtual double area() const; }; 73 How do we implement Shape: : draw() ?
Inheritance & Interfaces • In this example, we never want to deal with objects of type Shape �Shape serves the role of an interface • All shapes need to be specific shapes that are instances of derived classes of Shape • How do we enforce this? Simple runtime mechanism: void Shape: : draw() const { assert(false); // we should never //call this method } 74
Pure Virtual We can specify that if we want the derived class to be non-abstract, draw() must be implemented in it, class Shape { public: virtual ~Shape() {}; // pure virtuals virtual void draw() const = 0; virtual double area() const = 0; }; 75
Pure Virtual We cannot create objects of a Pure Virtual class – that is an object that contains at least one Pure Virtual method Shape* p; // legal Shape s; // illegal p = new Shape; // illegal Circle c; // legal p = &c; // legal 76
Pure Virtual Dtor We can specify that if we want the derived class to be non-abstract, dtor must be implemented in it, class Shape { public: // pure virtuals virtual ~Shape()= 0; virtual void draw() const = 0; virtual double area() const = 0; }; inline Shape: : ~Shape() { } // What? ! 77
Pure Virtual Dtor We can specify that if we want the derived class to be non-abstract, dtor must be implemented in it, however, it can be implemented in base also, destructor will be called here so we must define it! class Shape { public: virtual ~Shape()= 0; virtual void draw() const = 0; virtual double area() const = 0; }; inline Shape: : ~Shape() { } // What? ! 78
Pure Virtual Dtor Having a pure virtual destructor is not very useful as all that it says is that the class is abstract and derived will be also abstract unless it will override the destructor and enforcing derived objects to implement a destructor does not make much sense since it is an implementation issue and not an interface one 79
Private Pure Virtual Legal and often used, derived objects must implement but cannot use: class Shape { virtual void draw. Impl()= 0; static unsigned int g_num. Draws; public: void draw() const { ++g_num. Draws; draw. Impl(); } . . . 80
Virtual Methods - Tips 1. If you have virtual methods in a class, always declare its destructor virtual 2. Never call virtual methods during construction and destruction 3. Use pure virtual classes without any fields to define interfaces 4. Use inheritance with polymorphism with care: Be sure that this is the appropriate solution ("is a" relation) 81
Interfaces • To create an equivalent to java interface – declare a base class with all methods pure virtual and no fields • Inheritance can be used to hide implementation. But, you will need a factory, and with templates also pimpl pattern (like we did in C’s List) 82
C++ pimpl In List. hpp file: In List. cpp file: struct Ilist: public List{ struct List { virtual void add() { virtual void add()=0; cout << "Add"; virtual ~List(){}; } static List* create(); virtual ~IList(){}; }; }; List* List: : create() { In main. cpp: return new IList; List* lp= List: : create(); } lp->add(); delete lp; 83
C++ pimpl See: http: //en. cppreference. com/w/cpp/language/pimpl for advanced material on pimpl in C++ 84
Method hiding
Method hiding (1) struct B { (virtual) void f(bool i) {cout << "bool" << endl; } }; struct D : public B { void f(int b) {cout << "int" << endl; } }; int main(){ D d; d. f(3); // prints ‘int’ d. f(true); // prints ‘int’ } 86
Method hiding (2) struct B { (virtual) void f(bool i) {cout << "bool" << endl; } }; struct D : public B { void f(int b) {cout << "int" << endl; } }; int main(){ D d; d. B: : f(true); // prints ‘bool’ d. B: : f(3); // prints ‘bool’ } 87
Method hiding (3) struct B { (virtual) void f(bool i) {cout << "bool" << endl; } }; struct D : public B { using B: : f; void f(int b) {cout << "int" << endl; } }; int main(){ D d; d. f(3); // prints ‘int’ d. f(true); // prints ‘bool’ } 88
Multiple inheritance and virtual base class 89
Multiple inheritance • A class can inherit from multiple classes: struct input. File{ void read(); }; struct output. File{ void write(); }; struct io. File : public input. File, public output. File{ … }; // in main io. File f; f. read(); f. write(); 90
Multiple inheritance order • Construction and destruction order are according to the inheritance list: struct input. File{ input. File(){cout<<“input. File ctor ”; } }; struct output. File{ output. File(){cout<<“output. File ctor ”; } }; struct io. File: public input. File, public output. File{ io. File(){cout<<“io. File ctor ”; } }; // in main io. File f; //prints: input. File ctor output. File ctor io. File ctor 91
Multiple inheritance • Name ambiguities will generate compile error. • In the following example io. File has two instances of open() struct input. File{ void open(); }; struct output. File{ void open(); }; struct io. File: public input. File, public output. File{ … }; // in main io. File f; f. open(); //error! f. input. File: : open(); //Ok! 92
Diamond Multiple Inheritance struct file{ file char* name; void open(); input. File } struct input. File : public file{ void read(); io. File }; struct output. File : public file{ void write(); }; struct io. File: public input. File, public output. File{}; // in main io. File f; f. open(); //error! f. input. File: : open(); //Ok! 93 ** io. File still has two instances of open() output. File
Diamond Multiple Inheritance struct file{ char* name; void open(); } struct input. File : public file{ void read(); }; struct output. File : public file{ void write(); }; struct io. File: public input. File, public output. File{}; // in main io. File f; f. name= “file. A. txt”; // error! f. input. File: : name=“file. A. txt”; // Ok! f. output. File: : name=“file. B. txt”; // Ok! Does not change input. File: : name 94
Virtual Inheritance struct file{ char* name; void open(); } struct input. File : virtual public file { void read(); }; struct output. File : virtual public file { void write(); }; struct io. File: public input. File, public output. File {}; // in main io. File f; f. open(); // Ok! // io. File has one instance of open() and name 95
Virtual inheritance: The base construction problem struct file{ file(char* name){…} char* _name; struct input. File: virtual public file{ input. File(char* name): file(name){} }; struct output. File: virtual public file{ output. File(char* name): file(name){} }; struct io. File: public input. File, public output. File{ io. File(char* name): input. File(name), output. File(name){} }; Problem: File ctor will be initialized twice! 96
Virtual inheritance – the solution: struct file{ file(char* name){…} char* _name; struct input. File: virtual public file{ input. File(char* name): file(name){} }; struct output. File: virtual public file{ output. File(char* name): file(name){} }; struct io. File: public input. File, public output. File{ io. File(char* name): file(name), input. File(name), output. File(name){} }; Solution: the base class is initialized by the most derived class 97
Virtual Base Class - D has to initialize A ! A constructors for virtual base classes anywhere in your class's inheritance hierarchy are called by the "most derived" class's constructor B 2 B 3 C D 98
Interim Summary • A known problem, easy to misuse. • Usually restrict yourself to “interface like” multiple inheritance: • <=1 "real" base and • >=0 "interface" like (only pure virtual functions (no data members and no implementation) 99
C-tors execution order • virtual base classes anywhere in the hierarchy. • • After all virtual base class constructors are finished: from base class to derived class. • 100 They are executed in the order they appear in a depth -first left-to-right traversal of the graph of base classes, where left to right refer to the order of appearance of base class names The order is determined by the order that the base classes appear in the declaration of the class, not in the order that the initializer appears in the derived class's initialization list (compilers often give warnings)
Consider the following case: struct first. Generation 1{ first. Generation 1(){cout<<"first gen 1n"; } }; struct first. Generation 2{ first. Generation 2(){cout<<"first gen 2n"; } }; struct second. Generation 1: public first. Generation 1{ second. Generation 1(){cout<<"snd gen 1n"; } }; struct second. Generation 2: public first. Generation 2{ second. Generation 2(){cout<<"snd gen 2n"; } }; struct third. Generation 1: public second. Generation 1, virtual public second. Generation 2{ third. Generation 1(){cout<<"third. Generation 1n"; } }; struct fourth. Generation 1: public third. Generation 1{ fourth. Generation 1(){cout<<"fourth. Generation 1n"; } }; int main() { fourth. Generation 1 f; 101
The inheritance graph: first. Generation 1 first. Generation 2 second. Generation 1 second. Generation 2 third. Generation 1 fourth. Generation 1 • fourth. G 1 calls second. G 2 calls first. G 2 • fourth. G 1 calls third. G 1 calls second. G 1 calls first. G 1 • Output is: first. G 2, second. G 2, first. G 1, second. G 1, third. G 1, fourth. G 1 102
Polymorphism vs. Templates
Polymorphism vs. Templates • Templates compilation time is much longer than using inheritance. • Using templates enlarge the code size. • Compilation errors can be very confusing. • Templates running time is much faster than using inheritance. • Combined with inlining, templates can reduce runtime overhead to zero. 104
Polymorphism vs. Templates • Rule of thumb: • Templates are better for containers and standard algorithms (e. g. , stl) • Inheritance and polymorphism are better for user’s application logic description • You can actually combine them. • As always – think of your task. 105
C++ casting, RTTI
C style casting: • double d = 3. 0; int i = (int) d; • const int *c. P = &i; int *nc. P = (int*)cp; • double * d. P = (double*)ncp; • Base *base. P 1 = new Derived; Base *base. P 2 = new Base Derived *der. P = (der. P*) base. P; Derived *der. P 2 = (der. P*) base. P 2; 107
C++ style casting �static_cast<type>(expression) �const_cast<type>(expression) �reinterpret_cast<type>(expression) �dynamic_cast<type>(expression) 108
The ‘static_cast’ operator static_cast<type>(expression) Could be used to perform any cast there is a known method for Should be used for: �any cast that would have worked implicitly �standard or user-defined conversion �up-casts �when you are sure the cast is safe (e. g. , reversing an upcast) Safer that “old-style” casts �e. g. won’t cast int* to float* Failure causes a compiler error �No dynamic checking is done int i = static_cast<int>(12. 45); 109
The ‘const_cast‘ operator const_cast<type>(expression) Is used to remove const-ness: void g(C * cp); void f(C const* cp) { g(const_cast<C *>(cp)); } • Usually, you should design your variables/methods such that you won’t have to use const_cast. • Compile time operator • Can cause serious trouble 110
‘reinterpret_cast‘ operator reinterpret_cast<type>(expression) Is used to reinterpret byte patterns. double d(10. 2); char* d. Bytes = reinterpret_cast<char *>(&d); • Circumvents the type checking of c++. • Very implementation-dependent. • (Should be) used rarely. • Very dangerous! 111
‘reinterpret_cast‘ operator reinterpret_cast<type>(expression) Reminder: binary_output in stl_code 112
Run Time Type Information (RTTI) 113
Run Time Type Information (RTTI) – why? Problem: Up-casting works fine. �Treating sub-class as base class: Shape * s = new Circle(); Line What about down-casting? �might not be safe! �correctness cannot be determined by the compiler. Circle * c = (Circle*) s; 114 Circle
RTTI – Run Time Type Information Mechanisms for RTTI: 1. dynamic_cast operator 2. typeid operator (and type_info class) 115
The ‘dynamic_cast‘ operator dynamic_cast<T>(expression) Enables run-time type checking: When expression is a pointer: �Returns a valid pointer if expression really points to type T �null pointer value otherwise 116
The ‘dynamic_cast‘ operator dynamic_cast<T>(expression) Enables run-time type checking: When expression is a reference: �Returns a valid reference if expression is really of type T �Throws an exception when it fails (“bad_cast”) 117
Dynamic_cast : example Shape* s = container. pop(); Circle* c = dynamic_cast<Circle*>(s); if (c != nullptr) {// c is a circle c->set. Radius(42); } else { . . . } 118
dynamic_cast - more dynamic_cast<T>(expression) Note: • Used only on pointer or reference types. • Can be used for up-cast, down-cast, cross-cast • Only for types with virtual-functions (“Polymorphic types”) • These object have a space for the information about the type: the virtual function table 119
dynamic_cast: only for polymorphics class Circle : public Shape { virtual void draw(); } class Date : public Time { // Time has no virtual functions } void foo(Shape * s, Time * t) { Circle * c = dynamic_cast<Circle*>( s ); //ok Date * date = dynamic_cast<Date*>( t ); //compilation error } 120
RTTI : typeid operator 121
RTTI : typeid operator • Obtains info about an object/expression usage: typeid( obj ) (like “sizeof”) Example: Dog d; Cat c; cout << "d is a " << typeid(d). name() << ", c is a " << typeid(c). name() <<endl; Output (might be): d is a Dog, c is a Cat 122
RTTI : typeid operator • Obtains info about an object/expression usage: typeid( obj ) (like “sizeof”) Example: Dog d; Cat c; cout << "d is a " << typeid(d). name() << ", c is a " << typeid(c). name() <<endl; Output (becase it does not have to be the name of the type that the programmer used, it might also be): d is a 3 Dog, c is a 3 Cat 123
RTTI misuse void rotate( shape const& s ) { if (typeid(s) == typeid(Circle) ) //do nothing else if (typeid(s) == typeid(Triangle) ) //rotate Triangle else if (typeid(s) == typeid(Rectangle) ) //rotate Rectangle } • Use virtual functions (i. e. polymorphism) when you can ! • Misuse of RTTI 124
- Insidan region jh
- Similar disuelve a similar
- Similar disuelve a similar
- Similar disuelve a similar
- Similar sire similar scion
- Identify the coordinating ideas expressed in similar form
- Ideas have consequences bad ideas have victims
- Ideas principales e ideas secundarias
- Voltaire main ideas
- Voltaire john locke
- Voltaire main ideas
- Main ideas in a paragraph
- Thomas hobbes enlightenment beliefs
- Christianity main ideas
- Enlightenment thinkers chart
- Renaissance humanism main idea
- Anthropology from a pragmatic point of view
- Hume's fork examples
- Stated main idea adalah
- What is an implied main idea
- Sample paragraph with main idea and supporting details
- Main ideas of existentialism
- Implied main idea definition
- Townsend press chapter 4 implied main ideas
- Puritanism main ideas
- Ways of expressing future time
- Void main int main
- Hát kết hợp bộ gõ cơ thể
- Bổ thể
- Tỉ lệ cơ thể trẻ em
- Gấu đi như thế nào
- Chụp tư thế worms-breton
- Chúa yêu trần thế
- Môn thể thao bắt đầu bằng chữ f
- Thế nào là hệ số cao nhất
- Các châu lục và đại dương trên thế giới
- Công thức tính độ biến thiên đông lượng
- Trời xanh đây là của chúng ta thể thơ
- Mật thư tọa độ 5x5
- 101012 bằng
- độ dài liên kết
- Các châu lục và đại dương trên thế giới
- Thể thơ truyền thống
- Quá trình desamine hóa có thể tạo ra
- Một số thể thơ truyền thống
- Cái miệng xinh xinh thế chỉ nói điều hay thôi
- Vẽ hình chiếu vuông góc của vật thể sau
- Nguyên nhân của sự mỏi cơ sinh 8
- đặc điểm cơ thể của người tối cổ
- Thế nào là giọng cùng tên?
- Vẽ hình chiếu đứng bằng cạnh của vật thể
- Vẽ hình chiếu vuông góc của vật thể sau
- Thẻ vin
- đại từ thay thế
- điện thế nghỉ
- Tư thế ngồi viết
- Diễn thế sinh thái là
- Dạng đột biến một nhiễm là
- Các số nguyên tố là gì
- Tư thế ngồi viết
- Lời thề hippocrates
- Thiếu nhi thế giới liên hoan
- ưu thế lai là gì
- Khi nào hổ con có thể sống độc lập
- Sự nuôi và dạy con của hươu
- Sơ đồ cơ thể người
- Từ ngữ thể hiện lòng nhân hậu
- Thế nào là mạng điện lắp đặt kiểu nổi
- Prisma model inheritance
- Object diagram java
- Priority inheritance
- Donna malayeri
- Inheritance of loss
- Thalassemia
- Rails sti vs polymorphic
- Punnett square hemophilia
- Sexlinked inheritance
- Inheritance of quantitative traits
- Niv proverbs 13
- Tujuan inheritance
- Contoh multilevel inheritance
- Pedigree sumbols
- Complete dominance pattern of inheritance
- Oop virtual
- Maternal effect and maternal inheritance
- Non mendelian inheritance
- Human inheritance modern genetics answer key
- Modern genetics human inheritance answer key
- Modern genetics human inheritance answer key
- Epistatic inheritance
- Mendel's 3rd law of inheritance
- Hemophilia mode of inheritance
- Perservefamily/status/
- Dominant genetic variance
- Private inheritance
- Spanish inheritance tax valencia region
- Hierarchical inheritance in c++
- Overloading and overriding
- Advantages and disadvantages of inheritance in java
- Private inheritance
- Complete dominance pattern of inheritance
- Inheritance of quantitative traits
- Sean blaine
- Mendel
- Use case inheritance
- Complex patterns of inheritance
- Inheritance characteristics
- Chapter 16 the molecular basis of inheritance
- Maternal effect and maternal inheritance
- Chapter 15: the chromosomal basis of inheritance
- Section 12-1 chromosomes and inheritance
- Chapter 11 complex inheritance and human heredity test
- The pedigree below traces the inheritance of alkaptonuria
- C++ advantages
- Inheritance of abo blood group
- Andrea morichetta
- Autosomal recessive inheritance
- Oops abstraction encapsulation inheritance polymorphism
- Inheritance.ilmsummit
- Polygenic inheritance
- Jenis jenis inheritance
- Autosome
- Encapsulation inheritance polymorphism
- The pedigree below traces the inheritance of alkaptonuria