Theory
એક જ loop એ દરેક card ને સેવા આપવી પડે
બંધ કરવાનો સમય. Till આજના swipes પર loop ચલાવીને discounts ગણે છે:
for each Card *c in swipes: total += c->discount();
યાદીમાં StudentCards અને StaffCards ભળેલાં છે, અને આવતા વર્ષે GuestCards જોડાશે. Loop એક જ લીટી રહેવું જોઈએ, છતાં દરેક card એ પોતાનો નિયમ લગાડવો જોઈએ.
Run-time polymorphism નું વચન તમે બે પાઠ પહેલાં જોયું હતું. આજે તમે એ બે શબ્દોને મળો છો જે એને ખરેખર પૂરું પાડે છે: virtual, અને એનું વધુ કડક ભાઈબંધ = 0.
Theory
કોરું menu નું પાટિયું
મુખ્ય કચેરી દરેક franchise માં menu ના પાટિયાનો નમૂનો લટકાવે છે: એના પર "આજનું discount" નું ખાનું છાપેલું છે, પણ મુખ્ય કચેરી મૂલ્ય કોરું છોડે છે, દરેક શાખાએ પોતાનું ભરવાનું છે.
Virtual function એ પાટિયાની એવી નોંધ છે જે શાખાઓ ફરી લખી શકે છે. Pure virtual function એ કોરું ખાનું છે: મુખ્ય કચેરી એવી શાખા ખોલવાની ના પાડે છે જેણે એ ભર્યું ન હોય. નમૂનો પોતે એવી દુકાન નથી જેમાં તમે ચાલીને જઈ શકો.
Theory
Virtual function, ઔપચારિક રીતે
Virtual function એ base class માં virtual સાથે declare થયેલું member function છે:
virtual double discount() { return 0.0; }
એની તાકાત base class ના pointers સાથે દેખાય છે: Card *c = new StudentCard; પછી c->discount() એ StudentCard ની આવૃત્તિ ચલાવે છે, કારણ કે virtual એ call ને late binding પર ફેરવે છે (run ના સમયે ખરેખરા object પ્રમાણે નક્કી થતું).
virtual વગર pointer નો પોતાનો પ્રકાર જીતે છે અને base ની આવૃત્તિ ચાલે છે: એ એક શબ્દ જ આખો ફરક છે.
Theory
Pure virtual, ઔપચારિક રીતે
શરીરને બદલે = 0 લખો અને function pure virtual બની જાય છે:
virtual double discount() = 0;
બે પરિણામ, બંને પરીક્ષાનું સોનું:
- Class એ abstract class બની જાય છે: એના objects બનાવવા એ compile ની ભૂલ છે.
- દરેક derived class એ pure virtual function ને override કરવું જ પડે, નહીં તો એ પોતે પણ abstract જ રહે છે.
Abstract class એ કરાર છે: એ કહે છે "દરેક card ને discount નો નિયમ હશે", નિયમ શું છે એ જાણવાનો ડોળ કર્યા વગર.
Practical
કરાર અને એના પર સહી કરનારા
#include <iostream>
using namespace std;
class Card { // abstract class
public:
virtual double discount() = 0; // pure virtual: the blank slot
virtual ~Card() {} // virtual destructor: good practice
};
class StudentCard : public Card {
public:
double discount() { return 0.10; } // must implement
};
class StaffCard : public Card {
public:
double discount() { return 0.20; } // must implement
};
int main() {
// Card c; // ERROR: cannot create abstract class object
Card *swipes[2] = { new StudentCard, new StaffCard };
for (int i = 0; i < 2; i++)
cout << swipes[i]->discount() << endl; // 0.1 then 0.2
delete swipes[0]; delete swipes[1];
return 0;
}
Think first
બંને outputs ધારો
ઉપરનો code લો અને discount() ને virtual શબ્દ વગર કલ્પો (અને = 0 વગર, એને 0.0 પાછું આપતું શરીર આપો). ત્યારે loop શું છાપે છે? અને જેમ લખાયેલો છે એ code સાથે?
Show the answer
virtual વગર: pointers એ Card છે, એટલે early binding Card ની આવૃત્તિ બે વાર બોલાવે છે: એ 0 અને 0* છાપે છે. સંતાનોના નિયમો અસ્તિત્વમાં તો છે પણ base ના pointer દ્વારા ક્યારેય પહોંચાતું નથી.
જેમ લખાયેલો છે તેમ (virtual): late binding દરેક ખરેખરા object ને પૂછે છે, અને 0.1 પછી 0.2 છપાય છે.
એ જ loop, એક શબ્દનો ફરક. જો પરીક્ષા આ જોડ દેખાડીને outputs પૂછે, તો હવે તમારી પાસે બંને છે.
Quiz
class Card માં virtual double discount() = 0; છે. એક student main() માં Card c; લખે છે. Compiler શું કહે છે?
- ભૂલ: Card એ abstract class છે, એના objects બનાવી શકાતા નથી
- વાંધો નહીં: c.discount() ફક્ત 0 પાછું આપશે
- ભૂલ: classes માં અંક 0 હોઈ શકે નહીં
- વાંધો નહીં, પણ ફક્ત ત્યારે જ જ્યારે StudentCard ક્યાંક હોય
Show the answer
ભૂલ: Card એ abstract class છે, એના objects બનાવી શકાતા નથી
એક pure virtual function પણ Card ને abstract બનાવવા પૂરતું છે, અને abstract classes ના objects બની શકતા નથી: discount() ની પાછળ ચલાવવા માટે શાબ્દિક રીતે કોઈ code જ નથી. તમે Card નાં pointers અને references તો હજી declare કરી જ શકો છો (એ જ તો આખો મુદ્દો છે). વિકલ્પ B એ = 0 ને "0 પાછું આપે છે" સાથે ગૂંચવે છે: એનો અર્થ છે "કોઈ શરીર અસ્તિત્વમાં નથી", નહીં કે "શરીર શૂન્ય પાછું આપે છે".
Watch out
ચોકસાઈના ત્રણ મુદ્દા
1. = 0 નો અર્થ છે કોઈ અમલ નહીં, "શૂન્ય પાછું આપે છે" નહીં.
2. Pure virtual function ને override કરવાનું ચૂકતો derived class abstract જ રહે છે: કરાર કોઈ સહી કરે ત્યાં સુધી પીછો છોડતો નથી.
3. Abstract classes માં data members, સામાન્ય functions, constructors સુધ્ધાં હોઈ શકે છે; abstract હોવું ફક્ત સીધા objects ની મનાઈ કરે છે. "Abstract classes માં ફક્ત pure virtual functions જ હોય છે" લખવાથી એક mark જાય છે: એ વધુ કડક વસ્તુને interface શૈલી કહે છે, એ કોઈ ફરજિયાત નિયમ નથી.
Theory
એ ભાત જે તમે કાયમ ફરી વાપરશો
Abstract base વત્તા મૂર્ત સંતાનો એ ખરેખરા software નું હાડપિંજર છે: area() = 0 વાળો Shape, calcSalary() = 0 વાળો Employee, અને તમે ક્યારેય મળશો એ દરેક plugin ની વ્યવસ્થા. Interviews માં vtable નો ઉલ્લેખ થાય, ત્યારે એ ફક્ત એ શોધ-કોષ્ટક છે જે C++ આ run ના સમયના વળાંકને કામ કરાવવા બનાવે છે. પ્રયુક્તિ કરતાં ખ્યાલ ઉપર: હાથમાં base નું pointer, નિર્ણય ખરેખરા object નો.
Summary
Key takeaways
- virtual એ base pointer/reference દ્વારા થતા call ને derived ના override સુધી લઈ જાય છે (late binding).
- virtual વગર pointer નો પ્રકાર નક્કી કરે છે અને base ની આવૃત્તિ ચાલે છે.
- Pure virtual (= 0) ને શરીર હોતું નથી; એવું એક function class ને abstract બનાવે છે.
- Abstract classes ના objects બની શકતા નથી, પણ એમનાં pointers/references જ ખરા કામગરા છે.
- સંતાનોએ દરેક pure virtual function override કરવું પડે, નહીં તો એ abstract જ રહે.
- Abstract class = કરાર: દરેક card discount() વ્યાખ્યાયિત કરશે જ.
- Memory hook: કોરું menu નું પાટિયું જે દરેક શાખાએ ભરવું પડે.