Download presentation
Presentation is loading. Please wait.
1
Virtual Methods
2
Why virtual methods? Recall: In C++ with pointers and references to objects there is automatic conversion: derived → base. Recall: In C++ with pointers and references to objects there is automatic conversion: derived → base. with such a pointer or reference only members (fields, methods) declared in base class are accessible with such a pointer or reference only members (fields, methods) declared in base class are accessible having the declared type of ptr/ref the compiler will always use the base class member, even if the pointer points to an object of the derived class. having the declared type of ptr/ref the compiler will always use the base class member, even if the pointer points to an object of the derived class.
3
class point { int x,y; int x,y; public: void show(); // draws a point void show(); // draws a point void hide(); void hide();}; class circle: public point { int r; int r; public: void show(); // draws circle void show(); // draws circle void hide(); void hide();}; circle o; point &rp=o; rp.show(); // calls point::show
4
Why virtual methods? circle o; point &rp=o; rp.show(); // I want to call circle::show() ! How to achieve it? How to achieve it?
5
class point { int x,y; int x,y; public: char kind; char kind; void show(); //draws point void show(); //draws point point(int x, int y) point(int x, int y) :x(x), y(y), :x(x), y(y), { kind=‘p’; kind=‘p’; }}; Solution is imperfect Solution is imperfect Ok., I’d say more: it is wrong! Ok., I’d say more: it is wrong! Compiler is ready to do it for us Compiler is ready to do it for us class circle: public point { int r; int r;public: void show(); //draws circle void show(); //draws circle circle(int x, int y, int r) circle(int x, int y, int r) :point(x,y), r(r) :point(x,y), r(r) { kind='c'; kind='c'; }}; circle o; point &rp=o; if (rp.kind=='p') rp.point::show(); rp.point::show();else rp.circle::show(); rp.circle::show();
6
Virtual methods If we declare a method as virtual when we call a virtual method by its name the compiler will use the method from proper class (the class of the actual object pointed to), not the method defined by the declared type o pointer. If we declare a method as virtual when we call a virtual method by its name the compiler will use the method from proper class (the class of the actual object pointed to), not the method defined by the declared type o pointer. void virtual point::hide(); A method has to be declared virtual in base class, in derived classes it will be virtual too, the keyword virtual may but does not have to be used in derived classes A method has to be declared virtual in base class, in derived classes it will be virtual too, the keyword virtual may but does not have to be used in derived classes
7
class point { int x,y; int x,y; public: void virtual show(); void virtual show(); void virtual hide(); void virtual hide();}; class circle: public point { int r; int r; public: void show(); // virtual void show(); // virtual void hide(); // virtual void hide(); // virtual}; Virtual methods
8
Virtual methods – how it works? In the class where a virtual method will appear first, an additional hidden field will be added to each object — the address of virtual methods table (VMT). In the class where a virtual method will appear first, an additional hidden field will be added to each object — the address of virtual methods table (VMT). The size of the object will grow. (see → sizeof ) The size of the object will grow. (see → sizeof ) For an object whose class cannot be determined with no doubt at compile time, calls to methods declared virtual will be indirect (VMT will be used) For an object whose class cannot be determined with no doubt at compile time, calls to methods declared virtual will be indirect (VMT will be used) It is slower than a direct call, It is slower than a direct call, virtual methods are not expanded inline, virtual methods are not expanded inline, still it is quicker than implementing the effect manually (like above), still it is quicker than implementing the effect manually (like above), compiler does not make mistakes (errare humanum est – as you know). compiler does not make mistakes (errare humanum est – as you know).
9
Virtual methods – how it works? Calls by pointer and reference will be indirect Calls by pointer and reference will be indirect Calls by object will be direct Calls by object will be direct... so quicker; in this case even virtual methods may be inline.... so quicker; in this case even virtual methods may be inline. Note: methods may be inherited and called for an object of derived class, so calls to virtual methods from within other methods are also indirect! Note: methods may be inherited and called for an object of derived class, so calls to virtual methods from within other methods are also indirect!
10
class point { int x,y; int x,y; public: void virtual show(); void virtual show(); void virtual hide(); void virtual hide(); void move(int dx, int dy) void move(int dx, int dy) { hide(); // virtual in point hide(); // virtual in point x+=dx; x+=dx; y+=dy; y+=dy; show(); // virtual in point show(); // virtual in point }}; class circle: public point { int r; int r; public: void show(); void show(); void hide(); void hide();}; circle o; point &rp=o; rp.show(); // calls circle::show() rp.move(); //inherited point::move calls //circle::show and circle::hide !!!
11
Polymorphic class A class is called polymorphic if it contains at least one virtual method A class is called polymorphic if it contains at least one virtual method Polymorphism usage in practice: Polymorphism usage in practice: We declare a list of pointers to points (polymorphic class) – we put points, circles and other figures on the list. We declare a list of pointers to points (polymorphic class) – we put points, circles and other figures on the list. Having a pointer we may tell each object to show itself (indirect call to virtual show()), Having a pointer we may tell each object to show itself (indirect call to virtual show()), We may move figures with non-virtual move(), but it will call virtual show() and hide() properly. We may move figures with non-virtual move(), but it will call virtual show() and hide() properly.
12
Early and late binding Early binding: Early binding: When a method is not virtual, or the class can be unequivocally determined at compile time, the method call is linked to the code (or the method is expanded inline) at linking stage. When a method is not virtual, or the class can be unequivocally determined at compile time, the method call is linked to the code (or the method is expanded inline) at linking stage. Late binding Late binding The proper virtual method is determined from actual type of the object at run time. The proper virtual method is determined from actual type of the object at run time.
13
Early and late binding Non-virtual methods – always early binding Non-virtual methods – always early binding Virtual method not always is subject to late binding. It will be linked early if: Virtual method not always is subject to late binding. It will be linked early if: We explicitly use the class name and scope operator (::), We explicitly use the class name and scope operator (::), We call the method for direct object (neither a pointer nor reference). We call the method for direct object (neither a pointer nor reference).
14
Virtual methods advantage: applications easy to develop, advantage: applications easy to develop, Writing our code we may use methods that have not been written yet! Writing our code we may use methods that have not been written yet! We do not have to copy the same code to many different classes (see: move() ). We do not have to copy the same code to many different classes (see: move() ). We do not risk to „enhance” the existing code with new errors. We do not risk to „enhance” the existing code with new errors.
15
Constructors and destructors Constructor may not be virtual. Anybody dares ask why?... Constructor may not be virtual. Anybody dares ask why?... Destructor may and sometimes should be virtual (now why?) Destructor may and sometimes should be virtual (now why?) Note: If we declare a destructor virtual, all his descendants – derived classes destructors – will also be virtual (do not bother that the names do not match, it does not matter). Note: If we declare a destructor virtual, all his descendants – derived classes destructors – will also be virtual (do not bother that the names do not match, it does not matter).
16
Static and virtual A static method may not be virtual. Anybody dares ask why?... He will not be forgiven... A static method may not be virtual. Anybody dares ask why?... He will not be forgiven...
17
Virtual methods inheritance A virtual method may be inherited A virtual method may be inherited It may be redefined; in its body a virtual method of base class may be called. It may be redefined; in its body a virtual method of base class may be called. example: example: void circle::show() { point::show(); // draw the center of circle point::show(); // draw the center of circle // draw the circle // draw the circle}
18
Overloading and virtuality Virtual methods have identical headers in all classes. The keyword virtual stands by the first declared. Virtual methods have identical headers in all classes. The keyword virtual stands by the first declared. Other methods (overloaded with different parameters) are regular methods/operators, are not virtual Other methods (overloaded with different parameters) are regular methods/operators, are not virtual Example of non-virtual method: Example of non-virtual method: void point::show(char * description){...};
19
Friend and virtual Virtuality is independent from friendship. Virtuality is independent from friendship. Friend feature is not transitive, Friend feature is not transitive, Friend access concerns only the method (class::method) which was declared friend, Friend access concerns only the method (class::method) which was declared friend, A method redefined in derived class (no matter if virtual) will not be automatically friend. A method redefined in derived class (no matter if virtual) will not be automatically friend.
20
Virtual methods accessibility Accessibility is determined at compile time Accessibility is determined at compile time Pointer/reference declared type decides. (like early binding – „early accessibility recognition”) Pointer/reference declared type decides. (like early binding – „early accessibility recognition”) Example: assume that all members of circle are private: Example: assume that all members of circle are private: circle c; point &rp=c; rp.show(); // OK – why?
21
Abstract class Abstract class may not produce any objects. Abstract class may not produce any objects. Abstract class is as a base class used to define a common „interface” – common features of a family of descendant derived classes (example: „figure”, „number” ) Abstract class is as a base class used to define a common „interface” – common features of a family of descendant derived classes (example: „figure”, „number” ) Abstract class inheritance Abstract class inheritance
22
Pure virtual method In C++ a class is abstract if it contains at least one pure virtual method – a virtual without a body. In C++ a class is abstract if it contains at least one pure virtual method – a virtual without a body. void virtual figure::draw()=0;
23
RTTI A pointer to base may be assigned the address to some descendant, therefore the declared pointer type does not fully determine the actual class of the object referred to. A pointer to base may be assigned the address to some descendant, therefore the declared pointer type does not fully determine the actual class of the object referred to. Sometimes at the run time we would like to determine the actual type of an object. If a polymorphic class is concerned, the object contains a special field that may be used to identify the class (it is a pointer to class’s VMT). With this field the RTTI mechanism may determine types at run time. Sometimes at the run time we would like to determine the actual type of an object. If a polymorphic class is concerned, the object contains a special field that may be used to identify the class (it is a pointer to class’s VMT). With this field the RTTI mechanism may determine types at run time. If the pointer or reference refers to standard type or non- polymorphic class, the type is determined according to declared type, and not the actual type of object – there is no other way to do it. If the pointer or reference refers to standard type or non- polymorphic class, the type is determined according to declared type, and not the actual type of object – there is no other way to do it.
24
RTTI RTTI — RunTime Type Information RTTI — RunTime Type Information operator typeid operator typeid type_info typeid(arg) arg: type, class, variable or object arg: type, class, variable or object
25
RTTI class type_info { // there’s private copy constructor and operator= // there’s private copy constructor and operator= // there’s no way to make a copy of this object from outside // there’s no way to make a copy of this object from outsidepublic: virtual ~type_info(); virtual ~type_info(); bool operator==(const type_info& rhs) const; bool operator==(const type_info& rhs) const; bool operator!=(const type_info& rhs) const; bool operator!=(const type_info& rhs) const; bool before(const type_info& rhs) const; bool before(const type_info& rhs) const; const char* name() const; const char* name() const;};
26
RTTI class A { virtual void a(){}; virtual void a(){};}; class B:public A {}; class C:public B {}; A a, *pa; C c; pa=&c; typeid(C)==typeid(pa)// 0 typeid(C)==typeid(pa)// 0 typeid(a)==typeid(*pa)// 0 typeid(a)==typeid(*pa)// 0 typeid(c)==typeid(*pa) // 1 typeid(c)==typeid(*pa) // 1 typeid(B).name() // B typeid(B).name() // B typeid(pa).name() // A * typeid(pa).name() // A * typeid(*pa).name() // C typeid(*pa).name() // C typeid(A).before(typeid(*pa)) // 1 typeid(A).before(typeid(*pa)) // 1 typeid(B).before(typeid(*pa)) // 1 typeid(B).before(typeid(*pa)) // 1 typeid(C).before(typeid(*pa)) // 0 typeid(C).before(typeid(*pa)) // 0 typeid(C).before(typeid(a)) // 0 typeid(C).before(typeid(a)) // 0
27
*_cast cast operators designed to replace C-style cast static_cast ( expression ) dynamic_cast ( expression ) reinterpret_cast ( expression ) const_cast ( expression ) these are opreators and 4 keywords of C++ these are opreators and 4 keywords of C++ designed to allow greater compiler-level and controll and runtime controll of (error prone) casts designed to allow greater compiler-level and controll and runtime controll of (error prone) casts allow to experss programmer’s intentions allow to experss programmer’s intentions
28
static_cast static_cast ( expression ) cast based on types known at the compile- time cast based on types known at the compile- time unsafe as the C cast: (type-id )expression unsafe as the C cast: (type-id )expression use with caution use with caution fast fast no changing of const or volatile qualifiers of experssion no changing of const or volatile qualifiers of experssion
29
static_cast static_cast ( expression ) class A {}; class B:public A { int method(); }; int fun(A * pa) int fun(A * pa){ static_cast (pa) -> method() // let’s hope pa points to B }
30
dynamic_cast dynamic_cast ( expression ) cast based on RTTI, for use with pointers and references cast based on RTTI, for use with pointers and references for pointers it returns NULL if type-id is neither type of expression nor experssion’s parent for pointers it returns NULL if type-id is neither type of expression nor experssion’s parent for references it throws exception if type-id is neither type of expression nor experssion’s parent for references it throws exception if type-id is neither type of expression nor experssion’s parent safe, but slower safe, but slower no changing of const or volatile qualifiers of experssion no changing of const or volatile qualifiers of experssion
31
dynamic_cast dynamic_cast ( expression ) class A {}; class B:public A {}; int fun() int fun(){ A *pa, *aptr=new A; B *pb, *bptr=new B;... pa=dynamic_cast (bptr); // OK pb=dynamic_cast (aptr); // NULL !!! pb=dynamic_cast (pa); // OK }
32
reinterpret_cast reinterpret_cast ( expression ) cast based on types known at the compile-time cast based on types known at the compile-time used for address (pointer) arithmetic used for address (pointer) arithmetic use for pointers and integers (to let the compiler know Your intence) use for pointers and integers (to let the compiler know Your intence) let Your boss think You’re a great guru of C++ programming ;) let Your boss think You’re a great guru of C++ programming ;) CLASS *ptr; CLASS *ptr;... unsigned int adress=reinterpret_cast (ptr); unsigned int adress=reinterpret_cast (ptr);
33
const_cast const_cast ( expression ) cast based on types known at the compile-time cast based on types known at the compile-time use for pointers and references use for pointers and references used for removing of const or volatile qualifiers of experssion used for removing of const or volatile qualifiers of experssion class CLASS { int member; int CLASS::constmethod() const { const_cast (this) -> member++; // const_cast (member)++; ERROR }}
34
mutable mutable keyword makes non-const non-static member variable non-const in const member functions (similar to static_cast) mutable keyword makes non-const non-static member variable non-const in const member functions (similar to static_cast) class CLASS { mutable int member; int CLASS::constmethod() const { member++; // since member is mutable }}
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.