Theory
બે નિર્ણય, બે ઘડિયાળ
ગઈ કાલે તમે till ને બે રીતે વર્તતું જોયું: bill(50) સામે bill(50, 0.1) જે compiler એ પસંદ કર્યું, અને p.discount() જે ખરેખરું card અડ્યું ત્યારે જ પસંદ થયું.
એ જ સ્તંભ, પણ નિર્ણયની ક્ષણ સાવ જુદી છે: એક પસંદગી program શરૂ થાય એ પહેલાં જ સીલ થઈ જાય છે, બીજી call ની ચોક્કસ ક્ષણ સુધી ખુલ્લી રહે છે.
પરીક્ષકોને આ વિરોધાભાસ બહુ ગમે છે: "compile-time અને run-time polymorphism ને અલગ પાડો" એ લગભગ ખાતરીબદ્ધ પ્રશ્ન છે. ચાલો આ ભેદ ભૂલવો અશક્ય બનાવીએ.
Theory
છાપેલું menu સામે રોજની ખાસ વાનગી
Canteen નું છાપેલું menu છાપખાનામાં જ નક્કી થઈ ગયું હતું: એમાંથી તમે જે મંગાવો, રસોડાનો પ્રતિભાવ ક્યારનોય નક્કી થઈ ચૂક્યો છે. એ compile-time છે: પીરસવાનું શરૂ થાય એ પહેલાં નક્કી.
રોજની ખાસ વાનગીનું પાટિયું દરરોજ સવારે એ દિવસે રસોડું સંભાળનાર નક્કી કરે છે. એ જ પાટિયું, ખરેખરા દિવસ પ્રમાણે જુદી વાનગી. એ run-time છે: જવાબ ફક્ત એ ક્ષણમાં જ અસ્તિત્વમાં આવે છે.
Theory
Binding: બંનેની પાછળનો શબ્દ
Binding એટલે function ના call ને એ શરીર સાથે જોડવું જે ચાલશે.
- Early (static) binding: જોડાણ compilation દરમિયાન નક્કી થાય છે. Compiler
bill(50, 0.1)વાંચે છે, દલીલોની યાદીને એક overload સાથે મેળવે છે, અને call ને પાકું જોડી દે છે. - Late (dynamic) binding: જોડાણ program ચાલતો હોય ત્યારે થાય છે.
p.discount()નું call p જે object નો ખરેખર ઉલ્લેખ કરે છે એની તરફ વળે છે, એ જ ક્ષણે તપાસાયેલું.
Compile-time polymorphism early binding વાપરે છે; run-time polymorphism late binding વાપરે છે.
At a glance
પરીક્ષાનું કોષ્ટક
| પાસું | Compile-time | Run-time |
|---|---|---|
| બીજું નામ | Static, early binding | Dynamic, late binding |
| ક્યારે નક્કી થાય | Compilation દરમિયાન | ચાલવા દરમિયાન |
| કઈ રીતે સિદ્ધ થાય | Function વત્તા operator overloading | Virtual functions વત્તા inheritance |
| Inheritance જોઈએ? | ના | હા, base pointer/reference સાથે |
| ઝડપ | વધુ ઝડપી (call પાકું જોડાયેલું) | થોડું ધીમું (શોધીને જોડાય) |
| લવચીકતા | Build વખતે નિશ્ચિત | ખરેખરા object પ્રમાણે ગોઠવાય |
Practical
એક જ program માં બંને ઘડિયાળ
#include <iostream>
using namespace std;
class Person {
public:
virtual double discount() { return 0.0; } // virtual: late binding
};
class Student : public Person {
public:
double discount() { return 0.10; } // overrides Person's
};
// COMPILE-TIME: two overloads, picked by argument list
double bill(double amt) { return amt; }
double bill(double amt, double disc) { return amt * (1 - disc); }
int main() {
cout << bill(50.0) << endl; // compiler chose overload 1
cout << bill(50.0, 0.2) << endl; // compiler chose overload 2
Person *p = new Student(); // base pointer, derived object
cout << p->discount() << endl; // 0.10: decided AT RUN TIME
delete p;
return 0;
}
Think first
એક શબ્દ કાઢો, જવાબ બદલાય
ઉપરના code માં, Person::discount() માંથી virtual શબ્દ કાઢી નાખો. હવે p->discount() શું છાપે છે, અને શા માટે?
Show the answer
એ 0 છાપે છે, એટલે કે Person ની આવૃત્તિ. virtual વગર, compiler call ને પહેલેથી, pointer ના પ્રકાર પ્રમાણે જોડે છે: p એ Person નું pointer છે, એટલે Person::discount() પાકું જોડાઈ જાય છે, ત્યાં ખરેખર ગમે તે object વસતો હોય. એક શબ્દ એ early અને late binding વચ્ચેનો આખો ફરક છે, અને એટલે જ પરીક્ષાઓ virtual સાથે અને વગર output પૂછવાનું ચૂકતી નથી.
Quiz
Run-time polymorphism વિશે કયું વિધાન **સાચું** છે?
- એને inheritance જોઈએ છે અને એ virtual functions દ્વારા સિદ્ધ થાય છે
- એ compile-time polymorphism કરતાં ઝડપી છે કારણ કે નિર્ણયો તાજા હોય છે
- Function overloading એ એનું સૌથી સામાન્ય ઉદાહરણ છે
- Compiler દલીલોના પ્રકાર તપાસીને એને ઉકેલે છે
Show the answer
એને inheritance જોઈએ છે અને એ virtual functions દ્વારા સિદ્ધ થાય છે
Run-time polymorphism ફક્ત inheritance ની ક્રમવ્યવસ્થામાં જ અસ્તિત્વમાં આવે છે, અને base pointers/references દ્વારા virtual functions થી વળે છે. એ સહેજ ધીમું છે (program call ના સમયે લક્ષ્ય શોધે છે), ઝડપી નહીં, એટલે B ખોટું છે. C અને D એ compile-time polymorphism વર્ણવે છે: overloading, જે compilation દરમિયાન દલીલોની યાદી પરથી ઉકેલાય છે. અહીં બે કુટુંબ અદલાબદલ કરવાં એ marks ગુમાવવાની જાણીતી રીત છે.
Watch out
જવાબો ક્યાં marks ગુમાવે છે
પરીક્ષકો ચકાસે એવા ચોકસાઈના ત્રણ મુદ્દા:
- Compile-time માટે "early/static binding" અને run-time માટે "late/dynamic binding" લખો; આ સમાનાર્થી જ marks છે.
virtualવગરનું overriding એ run-time polymorphism નથી: base નું pointer હજી base ની આવૃત્તિ જ બોલાવે છે.- Templates પણ compile-time polymorphism ગણાય છે; એમનો ઉલ્લેખ ફક્ત ત્યારે કરો જ્યારે તમારું પેપર એમને આવરી લેતું હોય, નહીં તો overloading પર જ ટકી રહો.
Theory
હંમેશા કામ કરતો અંગૂઠાનો નિયમ
એક પ્રશ્ન પૂછો: શું compiler ને પહેલેથી ખબર પડી શકતી હતી? જો દલીલોની યાદી નક્કી કરતી હોય (overloading), તો હા, એટલે compile-time. જો જવાબ એના પર આધારિત હોય કે ચાલતી વખતે pointer પાસે કયો object હોય છે, તો ના, એટલે run-time. હવે પછીના પાઠો દરેક કુટુંબમાં ઊંડે ઊતરે છે: પહેલાં overloading સામે overriding, પછી virtual functions પોતે.
Summary
Key takeaways
- Binding = call ને function ના શરીર સાથે જોડવું; early binding compilation વખતે, late binding ચાલવા વખતે.
- Compile-time polymorphism: function/operator overloading, દલીલોની યાદી પરથી ઉકેલાય, વધુ ઝડપી.
- Run-time polymorphism: base pointers/references દ્વારા virtual functions વત્તા inheritance, લવચીક.
- virtual શબ્દ વગર pointer નો પ્રકાર નક્કી કરે છે: base ની આવૃત્તિ ચાલે છે (early binding).
- Run-time ને inheritance જોઈએ; compile-time ને નહીં.
- Memory hook: છાપેલું menu સામે રોજની ખાસ વાનગીનું પાટિયું.