View
217
Download
0
Embed Size (px)
Citation preview
VVirtual Methodirtual Methodss
Why virtual methods?Why virtual methods?
Recall:Recall: In C++ with pointers and references to In C++ with pointers and references to objects there is automatic conversion:objects there is automatic conversion:
derived derived → → base.base. with such a pointer or reference with such a pointer or reference
only membersonly members (fields, methods)(fields, methods) declared in declared in basebase class class are accessibleare accessible
having the having the declareddeclared type of ptr/ref the compiler type of ptr/ref the compiler will always use the base class member, even if the will always use the base class member, even if the pointer points to an object of the derived class. pointer points to an object of the derived class.
class pointclass point{{ int x,y;int x,y; public:public: void show(); // draws a pointvoid show(); // draws a point void hide();void hide();};};class circle: public pointclass circle: public point{{ int r;int r; public:public: void show(); // draws void show(); // draws circlecircle void hide();void hide();};};
circle o;circle o;point &rp=o;point &rp=o;rp.show(); rp.show(); // calls point::show// calls point::show
Why virtual methods?Why virtual methods?
circle o;circle o;
point &rp=o;point &rp=o;
rp.show(); rp.show(); // // I want to call circleI want to call circle::show::show() !() !
How to achieve itHow to achieve it??
class pointclass point{{ int x,y;int x,y; public:public: char kind;char kind; void show(); //draws pointvoid 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 imperfectSolution is imperfect Ok., I’d say more: it is wrong!Ok., I’d say more: it is wrong! CompilerCompiler is ready to do it for us is ready to do it for us
class circle: public pointclass circle: public point{{ int r;int r;public:public: void show(); //draws void show(); //draws circlecircle 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;circle o;point &rp=o;point &rp=o;if (rp.kind=='p')if (rp.kind=='p') rp.point::show(); rp.point::show(); elseelse rp.circle::show(); rp.circle::show();
Virtual methodsVirtual methods If we declare a method as If we declare a method as virtualvirtual
when we call a virtual method by its namewhen we call a virtual method by its namethe compiler will use the method from proper class the compiler will use the method from proper class (the class of the actual object pointed to)(the class of the actual object pointed to), , not the method defined by the declared type o pointernot the method defined by the declared type o pointer..
void void virtualvirtual pointpoint::::hidehide();();
A method has to be declared A method has to be declared virtualvirtual in base class, in base class, in derived classes it will be virtual too, the keyword in derived classes it will be virtual too, the keyword virtualvirtual maymay but does not have to be used in but does not have to be used in derived classesderived classes
class pointclass point
{{
int x,y;int x,y;
public:public:
void void virtualvirtual show(); show();
void void virtualvirtual hide(); hide();
};};
class circle: public pointclass circle: public point
{{
int r;int r;
public:public:
void show(); void show(); // virtual// virtual
void hide(); void hide(); // virtual// virtual
};};
Virtual methodsVirtual methods
Virtual methods – how it works?Virtual methods – how it works? In the class where a virtual method will appear first, an In the class where a virtual method will appear first, an
additional hidden field will be added to each object — the additional hidden field will be added to each object — the address of virtual methods table (VMT).address of virtual methods table (VMT). The size of the object will grow. (see The size of the object will grow. (see →→ sizeofsizeof) )
For an object whose class cannot be determined with no doubt For an object whose class cannot be determined with no doubt at compile time, calls to methods declared virtual will be at compile time, calls to methods declared virtual will be indirectindirect (VMT will be used) (VMT will be used) It is slower thIt is slower thanan a direct ca a direct calll,l, virtual methodvirtual methods are not expanded s are not expanded inlineinline,, still it is quicker than implementing the effect manually (like above),still it is quicker than implementing the effect manually (like above), comcompilpiler does not make mistakeser does not make mistakes ( (errare humanum esterrare humanum est – – as you as you
knowknow).).
Virtual methodsVirtual methods – how it works? – how it works? Calls by pointer and reference will be indirectCalls by pointer and reference will be indirect
Calls by object will be directCalls by object will be direct ... so quicker; in this case even virtual methods... so quicker; in this case even virtual methods may be may be
inline.inline.
NoteNote: : methods may be inherited and called for an methods may be inherited and called for an object of derived class, so calls to virtual methods object of derived class, so calls to virtual methods from within other methods are also indirectfrom within other methods are also indirect! !
class pointclass point{{ int x,y;int x,y; public: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(); hide(); // virtual in point// virtual in point x+=dx;x+=dx; y+=dy;y+=dy; show(); show(); // virtual in point// virtual in point }}};};
class circle: public pointclass circle: public point{{ int r;int r; public:public: void show(); void show(); void hide();void hide();};}; circle o;circle o;point &rp=o;point &rp=o;rp.show(); rp.show(); // calls circle::show()// calls circle::show()
rp.move(); rp.move(); ////inherited inherited point::move calls point::move calls //circle::show and circle::hide !!!//circle::show and circle::hide !!!
PolymorphiPolymorphicc class class A class is called A class is called polymorpolymorphphicic if it contains at least if it contains at least
one one vvirtual metirtual methhodod
PPolymorphismolymorphism usage in practice: usage in practice: We declare a list of pointers to pointsWe declare a list of pointers to points ((polymorphipolymorphic classc class) )
– we put points, – we put points, circlescircles and and other figuresother figures on the list on the list.. Having a pointer we may tell each object to show itself Having a pointer we may tell each object to show itself
((indirect call to virtual show()indirect call to virtual show()), ), We may move figures with non-virtual We may move figures with non-virtual move()move(), but it will , but it will
call virtual call virtual show()show() and and hide()hide() properly properly. .
Early and late bindingEarly and late binding
Early bindingEarly binding:: When a method is not virtual, or the class can be When a method is not virtual, or the class can be
unequivocalunequivocally determined at compile time, the ly determined at compile time, the method call is linked to the code (or the method is method call is linked to the code (or the method is expanded inline) at expanded inline) at linkinglinking stage stage..
Late bindingLate binding The proper virtual method is determined from The proper virtual method is determined from
actual type of the object at actual type of the object at runrun time time..
Early and late bindingEarly and late binding
Non-virtual methods – always early bindingNon-virtual methods – always early binding
Virtual method not always is subject to late Virtual method not always is subject to late binding. It will be linked binding. It will be linked earlyearly if: if: We explicitly We explicitly use the use the class name and scope class name and scope
operator (::), operator (::), We call the method for direct object (neither a We call the method for direct object (neither a
pointer nor reference)pointer nor reference)..
VVirtual irtual mmethodethodss
advantageadvantage:: applications easy to develop applications easy to develop , , Writing our code we may use methods that have Writing our code we may use methods that have
not been written yet!not been written yet! We do not have to copy the same code to many We do not have to copy the same code to many
different classes different classes ((see:see: move(move())). ). We do not risk to „enhance” the existing code with We do not risk to „enhance” the existing code with
new errorsnew errors..
CConstructoronstructorss andand destructors destructors
CConstruonstrucctor tor may may notnot be virtual. be virtual.Anybody dares ask why?...Anybody dares ask why?...
DestruDestrucctor tor maymay and sometimes and sometimes shouldshould be be virtual (virtual (now whynow why?)?) NoteNote: : If we declare a destructor If we declare a destructor virtualvirtual, all his , all his
descendantdescendants – derived classes destructors – will s – derived classes destructors – will also be also be virtualvirtual ((do not bother that the names do not do not bother that the names do not match, it does not mattermatch, it does not matter).).
Static Static andand virtual virtual
A static mA static metethhodod may may notnot be be vvirtualirtual.. Anybody dares ask why?... He will not be forgiven...Anybody dares ask why?... He will not be forgiven...
VVirtual irtual mmethodethods inheritances inheritance
A vA virtualirtual method may be inherited method may be inherited It may be redefined; in its body a virtual method of base class It may be redefined; in its body a virtual method of base class
may be called.may be called.
exampleexample::
void void circlecircle::::showshow() ()
{{
pointpoint::::showshow(); // (); // draw the center of circledraw the center of circle
//// draw the circle draw the circle
}}
Overloading and vOverloading and virtualirtualityity
Virtual methods have identical headers in all classes.Virtual methods have identical headers in all classes. The keyword The keyword virtualvirtual stands by the first declared. stands by the first declared. Other Other metmethhododss ( (overloaded with different parametersoverloaded with different parameters) ) are are
regular regular metmethhododss/operator/operators, are not virtuals, are not virtual
Example of non-virtual Example of non-virtual metmethhod: od:
void void pointpoint::::showshow(char * (char * descriptiondescription){...}; ){...};
Friend and virtualFriend and virtual
VVirtualirtualityity isis independent from friendshipindependent from friendship. . Friend feature is not transitiveFriend feature is not transitive, , Friend access concerns only the method Friend access concerns only the method
(class::method)(class::method) which was declared friendwhich was declared friend,, A mA metethhodod redefined in derived class (no matter if redefined in derived class (no matter if
virtual) will not be automatically friendvirtual) will not be automatically friend..
VVirtual irtual mmethodethods accessibilitys accessibility
Accessibility is determined at compile timeAccessibility is determined at compile time Pointer/reference Pointer/reference declareddeclared type decides type decides..
(like early binding – „early accessibility recognition”)(like early binding – „early accessibility recognition”)
Example: assume that all members of Example: assume that all members of circlecircle are are privateprivate::
circlecircle cc;;ppointoint &rp= &rp=cc;;rp.rp.showshow(); (); // OK – // OK – whywhy??
AAbstrabstract classct class
AAbstrabstract classct class may not produce any objectsmay not produce any objects..
AAbstrabstract classct class is as a base class used to define is as a base class used to define a common „interface” – common features of a a common „interface” – common features of a family of family of descendantdescendant derived classes derived classes(example: (example: „figur„figuree””,, „ „numbernumber” ” ))
Abstract class inheritanceAbstract class inheritance
Pure virtual methodPure virtual method
In In C++ C++ a class is abstract if it contains at least a class is abstract if it contains at least one one purepure vvirtual irtual method method – – a virtual without a a virtual without a bodybody. .
void virtual figurvoid virtual figuree::::drawdraw()=0;()=0;
RTTIRTTI A pointer to base may be assigned the address to some A pointer to base may be assigned the address to some
descendant, therefore the descendant, therefore the declareddeclared pointer type does not fully pointer type does not fully determine the determine the actualactual class of the object referred to. class of the object referred to.
Sometimes at Sometimes at the the run time we would like to determine the run time we would like to determine the actual type of an object. If a polymorphic class is concerned, actual type of an object. If a polymorphic class is concerned, the object contains a special field that may be used to identify 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 the class (it is a pointer to class’s VMT). With this field the RTTI mechanism may determine types at run time. RTTI mechanism may determine types at run time.
If the pointer or reference refers to standard type or non-If the pointer or reference refers to standard type or non-polymorphic class, the type is determined according to polymorphic class, the type is determined according to declareddeclared type, and not the actual type of object – there is no type, and not the actual type of object – there is no other way to do it.other way to do it.
RTTIRTTI
RTTI — RTTI — RunTime Type InformationRunTime Type Information
operator typeidoperator typeid
type_info typeid(arg)type_info typeid(arg)
arg: typarg: typee, , classclass, , variablevariable or objector object
RTTIRTTI
class type_info class type_info {{ // // there’s there’s prprivateivate copy conscopy construtrucctor tor and and operatoroperator== // // there’s no way to make a copy of this object from outsidethere’s no way to make a copy of this object from outsidepublic:public: 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;};};
RTTIRTTI
class A class A { { virtual void a(){}; virtual void a(){}; };};class B:public A {};class B:public A {};class C:public B {};class C:public B {};
A a, *pa;A a, *pa;C c;C c;pa=&c;pa=&c;
typeid(C)==typeid(pa)typeid(C)==typeid(pa) // 0// 0 typeid(a)==typeid(*pa)typeid(a)==typeid(*pa) // 0// 0 typeid(c)==typeid(*pa) typeid(c)==typeid(*pa) // 1// 1 typeid(B).name() typeid(B).name() // B// B typeid(pa).name() typeid(pa).name() // A *// A * typeid(*pa).name() typeid(*pa).name() // C// C typeid(A).before(typeid(*pa)) typeid(A).before(typeid(*pa)) // 1// 1 typeid(B).before(typeid(*pa)) typeid(B).before(typeid(*pa)) // 1// 1 typeid(C).before(typeid(*pa)) typeid(C).before(typeid(*pa)) // 0// 0 typeid(C).before(typeid(a)) typeid(C).before(typeid(a)) // 0 // 0
*_cast*_castcast operators designed to replace C-style castcast operators designed to replace C-style cast
staticstatic_cast_cast << type-id type-id > > (( expression expression ))
dynamic_castdynamic_cast << type-id type-id > > (( expression expression ))
reinterpretreinterpret_cast_cast << type-id type-id > > (( expression expression ))
constconst_cast_cast << type-id type-id > > (( expression 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 designed to allow greater compiler-level and controll and runtime
controll of (error prone) castscontroll of (error prone) casts allow to experss programmer’s intentionsallow to experss programmer’s intentions
staticstatic_cast_caststaticstatic_cast_cast << type-id type-id > > (( expression expression ))
cast based on types known at the compile-cast based on types known at the compile-timetime
unsafe as the C cast: (unsafe as the C cast: (type-idtype-id ))expressionexpression use with cautionuse with caution fastfast
no changing of const or volatile qualifiers of no changing of const or volatile qualifiers of experssionexperssion
staticstatic_cast_caststaticstatic_cast_cast << type-id type-id > > (( expression expression ))
class A {};class A {};
class B:public Aclass B:public A{{
int method();int method();};};
int fun(A * pa)int fun(A * pa){{
static_cast<B*>(pa) -> method()static_cast<B*>(pa) -> method()// let’s hope pa points to B// let’s hope pa points to B
}}
dynamicdynamic_cast_castdynamicdynamic_cast_cast << type-id type-id > > (( expression expression ))
cast based on RTTI, for use with pointers cast based on RTTI, for use with pointers and referencesand references
for pointers it returns NULL if for pointers it returns NULL if type-idtype-id is neither type is neither type of of expressionexpression nor nor experssion’s experssion’s parentparent
for references it throws exception if for references it throws exception if type-idtype-id is neither is neither type of type of expressionexpression nor nor experssion’s experssion’s parentparent
safe, but slowersafe, but slower no changing of const or volatile qualifiers of no changing of const or volatile qualifiers of
experssionexperssion
dynamicdynamic_cast_castdynamicdynamic_cast_cast << type-id type-id > > (( expression expression ))
class A {};class A {};
class B:public Aclass B:public A{{};};
int fun()int fun(){{
A *pa, *aptr=new A;A *pa, *aptr=new A;B *pb, *bptr=new B;B *pb, *bptr=new B;......pa=dynamic_cast<A*>(bptr); pa=dynamic_cast<A*>(bptr); // OK// OKpb=dynamic_cast<B*>(aptr); pb=dynamic_cast<B*>(aptr); // NULL !!!// NULL !!!pb=dynamic_cast<B*>(pa); pb=dynamic_cast<B*>(pa); // OK// OK
}}
reinterpretreinterpret_cast_cast
reinterpret_reinterpret_castcast << type-id type-id > > (( expression expression ))
cast based on types known at the compile-timecast based on types known at the compile-time used for address (pointer) arithmeticused for address (pointer) arithmetic use for pointers and integers (to let the compiler know Your use for pointers and integers (to let the compiler know Your
intence)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<unsigned int>(ptr);unsigned int adress=reinterpret_cast<unsigned int>(ptr);
constconst_cast_castconstconst_cast_cast << type-id type-id > > (( expression expression ))
cast based on types known at the compile-timecast based on types known at the compile-time use for pointers and referencesuse for pointers and references used for removing of const or volatile qualifiers of used for removing of const or volatile qualifiers of
experssionexperssion
class CLASSclass CLASS{{
int member;int member;
int CLASS::constmethod() constint CLASS::constmethod() const{{
const_cast<CLASS *>(this) -> member++;const_cast<CLASS *>(this) -> member++;// const_cast<int>(member)++; // const_cast<int>(member)++; ERRORERROR
}}}}
mutablemutable mutable keyword makes non-const non-static mutable keyword makes non-const non-static
member variable non-const in const member member variable non-const in const member functionsfunctions (similar to static_cast)(similar to static_cast)
class CLASSclass CLASS{{
mutable int member;mutable int member;
int CLASS::constmethod() constint CLASS::constmethod() const{{
member++; member++; // since member is mutable // since member is mutable }}
}}