Access Specifiers in C++: हमने public, protected व private Access Specifier के बारे में इसी अध्याय में कुछ चर्चा की थी और समझने की कोशिश की थी कि किस प्रकार से ये Keywords Base Class के Members के Access को Control करते हैं। अभी तक हमने
class Derive : public Base
Format में Derive Classes बनाई है। यहां public Keyword ये बताता है कि Derive Class Base Class के केवल उन Members को Access कर सकता है जो Public Area में Define किए गए है। यदि हम
class Derive : private Base
Format में Derive Class बनाते हैं तो Base Class के किसी भी Member Function को Drive Class से Access नहीं कर सकते हैं। इसलिये हमें हमेंशा यहां public ही लिखना चाहिए। कई बार हमें ऐसी जरूरत होती है कि हम Base Class के Private Members को भी Access कर सकें। ऐसे में हमें protected Keyword का प्रयोग करना पडता है। यानी
class Derive : protected Base
Format में Derive Class को Use करना पडता है। साथ ही हमें जिन Members को Base Class से Derive Class में Use करना है, उन्हें उस Base Class में भी protected Area में Declare किए जाने जरूरी होते हैं। सारांश में Access Specifier की क्षमताओं को हम निम्न सारणी द्वारा Represent कर सकते हैं:
हालांकि, एक किसी Base Class को Inherit करके नई Class बनाई जाती है लेकिन फिर भी Base Class के Members की स्थिति में कोई परिवर्तन नहीं होता है। क्योंकि Base Class Derive Class के बारे में कुछ भी नहीं जानता है। इस सारणी से Access Specifier से Class के Members को किस हद तक Access किया जा सकता है, इसके बारे में प्राप्त जानकारी प्राप्त हो रही है। सबसे पहला सवाल तो यही पैदा होता है कि:
किसी Class के Data को Private रखा जाए या Protected?
हमने दोनों तरह के उदाहरण इस अध्याय में देखे हैं। यदि Base Class के Data को Protected रखा जाता है तो हमें ये सुविधा प्राप्त होती है कि Derived Class में Base Class के Data को Access करने के लिए Additional Base Class Functions को फिर से लिखने की जरूरत नहीं होती है।
लेकिन सामान्यतया Class के Data को Private ही रखना चाहिए। Public Data को Program का कोई भी Function Modify कर सकता है, इसलिए Public Data को हमेंशा ही Avoid करना चाहिए।
Protected Data उस Class के किसी भी Derived Class के लिए उपलब्ध रहते हैं, इसलिए Protected Data को Derived Class का कोई भी Member Function Modify कर सकता है। कोई भी एक Class को दूसरी Class में Derive करके Base Class के Protected Data को Access कर सकता है। इसलिए यही उचित रहता है कि Base Class के Data को कोई Derive Class भी Directly Access ना कर सके।
ध्यान दें कि किसी Class के वे Member Functions जो उस Class के Data को Access कर सकते हैं, उस Class के Interface होते हैं। इसलिए Class को इस तरह से Design करना चाहिए कि उस Class में दो Interfaces हों। एक Public Interface हो जिसका प्रयोग Class के Objects कर सकें और एक Protected Interface हो जिसका प्रयोग Derived Classes कर सकें। साथ ही ये दोनों Interfaces भी ऐसे होने चाहिएं कि वे Directly Base Class के Data को Access ना कर सकें। Base Class के Data को Private रखने का एक फायदा ये है कि हम इन्हें Derived Class में विभाजित किए बिना भी Change कर सकते हैं।
जब तक Class का Interface उपलब्ध रहता है, हम उस Class के Data को Change कर सकते हैं। हालांकि Derived Class के Member Functions को Base Class के Data को केवल Read करने की ही सुविधा देनी चाहिए। एक Derived Class को इस प्रकार का Read Only Access प्रदान करके हम get_ia() जैसे सरल Functions लिख सकते हैं। इन Functions को Protected रखना चाहिए, क्योंकि ये Functions Protected Interface के भाग हैं जिनका प्रयोग Derived Class द्वारा किया जाता है और इन्हें Non-Derived Class से Accessible नहीं होना चाहिए। यानी ये Protected Functions केवल Derived Class से Access नहीं होने चाहिएं। चलिए, इस Concept को ठीक से समझने के लिए एक उदाहरण देखते हैं:
// Superior stack created using inheritance, // base class data private; uses protected member function #include <iostream.h> #include <process.h> // for exit() class Stack // a stack holds up to SIZE ints { protected: enum {SIZE=20}; // capacity of stack private: int st[SIZE]; // integers are stored in array int top; // index of last item pushed protected: int get_top() const // return current top { return top; } public: Stack() // no-arg constructor { top = -1; } void push(int var) // place an item on the stack { st[++top] = var; } int pop() // remove an item from the stack { return st[top--]; } }; class Stack2 : public Stack { public: void push(int var) { if(get_top() >= SIZE-1) { cout << "Error: stack overflow"; exit(-1); } Stack::push(var); // call push() in Stack class } int pop() { if(get_top() < 0) { cout << "Error: stack underflow"; exit(-1); } return Stack::pop(); // call pop() in Stack class } }; void main() { Stack2 s; // create a Stack2 object s.push(11); // push 3 items onto stack s.push(12); s.push(13); cout << s.pop() << endl; // pop 3 items and display them cout << s.pop() << endl; cout << s.pop() << endl; cout << s.pop() << endl; // oops, popped one too many }
जैसाकि हम इस Program में देख सकते हैं Array st व Index top जो कि Stack Class Main Data Items हैं, Private Area में Declare किए गए हैं। Stack Class के केवल Member Functions ही इन Data को Access कर सकते हैं। जब हम Stack2 को Stack से Derive करते हैं, तो Stack2 के push() व pop() Member Functions Stack के push() व pop() Member Functions को Call कर सकते हैं। लेकिन Stack2 में हमें top के मान को भी Read करना है ताकि हम ये पता कर सकें कि Stack Full है या नहीं।
ऐसा सम्भव हो सके इसके लिए हमने get_top() नाम का एक Function Stack में Create किया है। ये Function Protected है इसलिए Derived Class इसे Execute कर सकता है। चूंकि ये निश्चित करने के लिए कि ये Protected Function Base Class Stack के Data को Modify ना कर सके, हमने इसे const रखा है। एक Normal Class User के रूप में Stack2 उसी तरह से काम करता है जिस तरह से Stack का इसी अध्याय में दिया गया पिछला Program काम करता है।
main() function तो बिल्कुल उसी तरह का है जैसा पिछले Program का था। लेकिन इस Program के Stack Class का Data पिछले Program की तुलना में अधिक सुरिक्षत है और इसके Data को कोई भी Class User Alter नहीं कर सकता है। सामान्य तौर पर Data को Protected रखने के बजाय इस प्रकार से Data को Use करना ज्यादा बेहतर तरीका है।
ध्यान दें कि हमने enum के Constant SIZE को Protected रखा है ताकि इसे Stack2 Derived Class में भी समान प्रकार से Use किया जा सके। क्योंकि SIZE को Array st को Define करने से पहले Define करना होता है, जो कि Private Area में है इसलिए हमने Stack Class में Data को दो Protected Sections में प्रयोग किया है।
चलिए, Access Specifier के Concepts को और अच्छी तरह से समझने के लिए हम एक और उदाहरण देखते हैं जिसमें Base Class में Data को Protected रखा गया है। इस Program में Inheritance को एक Design Element की तरह Use किया गया है ना कि Reuse Element की तरह। इस Program का उद्देश्य Screen पर विभिन्न प्रकार के Shapes को Draw करना है। यहां Draw किया जाने वाला Drawing किसी भी प्रकार से Graphical नहीं है। हम जो Graphics Draw कर रहे हैं वे एक Character X से Draw किए जा रहे हैं। लेकिन OOPS का Concept Actual Graphics की Drawing के लिए भी समान प्रकार से ही लागू होता है।
Access Specifiers in C++ – Hierarchy of Shapes
इस Program में एक Shape नाम की Base Class है और इसकी तीन Derived Classes Square, Cap व Bowl हैं। cap एक Pyramid Triangle है, जबकि bowl एक उल्टा पिरामिड है। हम इन Shapes की Size व Position को Argument के रूप में Specify करके Shapes को किसी भी Size का Create कर सकते हैं और Screen पर कहीं भी Display कर सकते हैं। उदाहरण के लिए
square(15, 2, 4);
Statement 1 By 6 Characters का X-Filled Square Create करता है, जो कि Upper Left Corner से 15 Columns Left में और 2 Row नीचे Draw होता है। ये Square Screen पर निम्नानुसार दिखाई देता है:
Access Specifiers in C++ – Shape Class
इस Class में ऐसे Elements हैं जो सभी प्रकार के Shapes के लिए Common रूप से Use होते हैं। ये Elements निम्नानुसार हैं:
- Object की Screen पर Position जिसे xCo व yCo द्वारा Represent किया गया है। और
- Object की Size जिसे size से represent किया गया है।
इन दोनों को यानी Position व Size दोनों को ही Characters से मापा गया है। position के दो भाग हैं।
- Screen के Left किनारे से Object के Left किनारे की दूरी (Distance) और
- Screen के Top Edge से Object के Top Edge की दूरी।
Size से Object की Height को तय किया जाता है। Shape में Protected Member Functions भी हैं जो उसके Private Data के लिए Read Only Access की सुविधा प्रदान करते हैं।
चूंकि Shape एक Abstract Class है इसलिए कभी भी इसका कोई Instance Create नहीं किया जा सकता है। इस Class के Constructors इन Access Functions के साथ Protected हो सकते हैं। square, cap व bowl Class के Constructors Base Class के Constructors और Member Functions को Drawing के लिए Call करते हैं। Shape का Program निम्नानुसार है:
// Program // draws shapes made from Xs on character-based display // base class data is private; uses protected access functions #include <iostream.h> #include <conio.h> class shape { private: int xCo, yCo; // coordinates of shape int size; // size of shape protected: // read-only functions int getx() const { return xCo; } int gety() const { return yCo; } int getz() const { return size; } void down() const; // declaration // 3-arg constructor shape(int x, int y, int s) : xCo(x), yCo(y), size(s) { } }; void shape::down() const // move cursor down to top of shape { for(int y=0; y<yCo; y++) cout << endl; } class square : public shape // square shape { public: // 3-arg constructor square(int x, int y, int s) : shape(x, y, s) { } void draw() const; // declaration }; void square::draw() const // draw a square { shape::down(); // position y at top of shape for(int y=0; y<getz(); y++) // move y down across shape { int x; for(x=1; x<getx(); x++) // space over to shape cout << ' '; for(x=0; x<getz(); x++) // draw line of Xs cout << 'X'; cout << endl; } } class cap : public shape // cap (pyramid) shape { public: // 3-arg constructor cap(int x, int y, int s) : shape(x, y, s) {} void draw() const; // declaration }; void cap::draw() const // draw a cap { shape::down(); for(int y=0; y<getz(); y++) { int x; for(x=0; x < getx()-y+1; x++) cout << ' '; for(x=0; x<2*y+1; x++) cout << 'X'; cout << endl; } } class bowl : public shape // bowl (inverted pyramid) shape { public: // 3-arg constructor bowl(int x, int y, int s) : shape(x, y, s) {} void draw() const; // declaration }; void bowl::draw() const // draw a bowl { shape::down(); for(int y=0; y<getz(); y++) { int x; for(x=0; x < getx()-(getz()-y)+2; x++) cout << ' '; for(x=0; x < 2*(getz()-y)-1; x++) cout << 'X'; cout << endl; } } void main() { bowl bw(10, 0, 3); // make a bowl bw.draw(); // draw it square sq(20, 1, 4); // make a square sq.draw(); // draw it cap cp(30, 1, 5); // make a cap cp.draw(); // draw it getch(); }
Output:
इस Program में shape Class का एक Member Function down() Cursor को Screen के Top से Shape के Top पर लाने और Shape को Draw करने के लिए जिम्मेदार है। इस Function को Derive Class के draw() Function ने Call किया है। हम इस विषय पर चर्चा नहीं करेंगे कि ये Shapes किस प्रकार से Draw हो रहे हैं बल्कि हम Classes के बीच की Relationship और Base Class के public व private Member Functions के उपयोग पर विचार करेंगे। ( Access Specifiers in C++ – Wiki )
ये Article इस वेबसाईट पर Selling हेतु उपलब्ध EBook C++ Programming Language in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी।
C++ Programming Language in Hindi | Page: 666 | Format: PDF