Size of Derived Objects: Concept को और अधिक Professional या उपयोगी बनाने के लिए हम ये मान लेते हैं कि Memory में जो भी Objects Store हो रहे हैं, उनकी Size एक समान नहीं है। ऐसी स्थिति तब होती है जब किसी एक Base Class से कई Classes Derived होती हैं।
उदाहरण के लिए Employee Program को देखिए जिसे अध्याय 7 में Define किया गया है। इसमें हमने एक Employee की Class बनायी है जो कि एक Base Class की तरह व्यवहार करती है और इससे तीन Class manager, scientist व laborer Classes को Derive किया है।
इन तीनों Classes के Objects अलग Size के हैं क्योंकि उनके Data Members की संख्या व Type अलग-अलग हैं। यानी इन तीनों Classes में Employee के नाम व Serial Number के अलावा कई Extra Data Members हैं।
अब हम ये चाहते हैं कि एक Array में Stored इन तीनों ही Classes के Objects के Address के आधार पर तीनों ही Classes के Objects के Data को एक Simple Loop और ofstream Class के write() Function का प्रयोग करके File में Store कर दें, जबकि write Function को Use करने के लिए हमें write Function के Second Argument में Object की Size देना जरूरी होता है।
मानलो कि हमारे पास employee Class के Objects के Pointers का एक Array arrap[] है। ये Pointers Employee Class के सभी Derived Classes के Objects को Point कर सकते हैं। इस Concept से सम्बंधित एक Program हमने अध्याय 9 में देखा है। हम जानते हैं कि यदि हम Virtual Functions को Use कर रहे हैं तो हम निम्नानुसार Statement लिख सकते हैं:
arrap[j]->putdata();
हम जानते हैं कि putdata() function का ये नया Version जो कि एक Virtual Function है, उस Object के putdata() Member Function को Call करता है, जिसके Object का Address Array में होता है, ना कि Base Class के putdata() Function को Call करता है। लेकिन क्या हम sizeof() Function को भी इस Derived Class के Object के Pointer के साथ Use करें, तो हमें ये Functions हर Class के Object की Size Return करेगा। यानी क्या हम निम्नानुसार Statement लिख सकते हैं:
ouf.write( (char*)arrap[j], sizeof(*arrap[j]) ); // Not Good
नहीं, हम ऐसा इसलिए नहीं कर सकते हैं क्योंकि sizeof() एक Virtual Function नहीं है। ये नहीं जानता है कि इसे उस Object की Size के बारे में पूछा जा रहा है, जिसका Pointer Array में Store है ना कि Object के Pointer की Size के बारे में पूछा जा रहा है। यानी ये function() हमेंशा Base Class के Object की Size ही Return करेगा।
Size of Derived Objects – The typeid( ) Function
हम उस Object की Size का पता कैसे लगा सकते हैं जिसका केवल Pointer ही हमारे पास है। इसका एक जवाब typeid() Function है जिसके बारे में हमने अध्याय 9 में बात की थी। हम इस Function का प्रयोग किसी Object की Class जानने के लिए कर सकते हैं कि अमुक Object किस Class का है और फिर उस Class के नाम को sizeof() Function में Use करके Object की Size ज्ञात कर सकते हैं।
यहां हम जो अगला उदाहरण Program बना रहे हैं, इसमें typeid() function को Use करके बताया जा रहा है कि हम इसे किस प्रकार से Object की Size ज्ञात करके इसके Data को File में Write करने के लिए Use कर सकते हैं।
इस Program में हमने Employee Class में एक साधारण सा User Interface Use किया है और कुछ Functions को Virtual बनाया है इसलिए हम Objects के Pointers का Array Create कर सकते हैं। साथ ही हमने इस Program में Error Handling से सम्बंधित कुछ Coding को भी Use किया है।
ये Program काफी हद तक एक Professional Program की तरह है। ये Program कई तकनीकों को Represent कर रहा है जिसे एक Full – Scale Database Management Program में Use किया जा सकता है। साथ ही ये Program OOPS की Real Power को भी Represent कर रहा है। हम इस Program द्वारा समझ सकते हैं कि किस प्रकार से हम एक Single Statement द्वारा विभिन्न Size के Objects के Data को File में Write कर सकते हैं।
// empl_io.cpp // performs file I/O on employee objects // handles different sized objects #include <fstream.h> // for file-stream functions #include <conio.h> // for getche() #include <process.h> // for exit() #include <typeinfo.h> // for typeid() const int LEN = 32; // maximum length of last names const int MAXEM = 100; // maximum number of employees enum employee_type {tmanager, tscientist, tlaborer}; class employee // employee class { private: char name[LEN]; // employee name unsigned long number; // employee number static int n; // current number of employees static employee* arrap[]; // array of ptrs to emps public: virtual void getdata() { cout << "\n Enter last name: "; cin >> name; cout << " Enter number: "; cin >> number; } virtual void putdata() { cout << "\n Name: " << name; cout << "\n Number: " << number; } virtual employee_type get_type(); // get type static void add(); // add an employee static void display(); // display all employees static void read(); // read from disk file static void write(); // write to disk file static void destroy(); // delete objects from memory }; // static variables int employee::n; // current number of employees employee* employee::arrap[MAXEM]; // array of ptrs to emps // manager class class manager : public employee { private: char title[LEN]; // "vice-president" etc. double dues; // golf club dues public: void getdata() { employee::getdata(); cout << " Enter title: "; cin >> title; cout << " Enter golf club dues: "; cin >> dues; } void putdata() { employee::putdata(); cout << "\n Title: " << title; cout << "\n Golf club dues: " << dues; } }; // scientist class class scientist : public employee { private: int pubs; // number of publications public: void getdata() { employee::getdata(); cout << " Enter number of pubs: "; cin >> pubs; } void putdata() { employee::putdata(); cout << "\n Number of publications: " << pubs; } }; // laborer class class laborer : public employee { }; // add employee to list in memory void employee::add() { cout << "\n'm' to add a manager" "\n's' to add a scientist" "\n'l' to add a laborer" "\nType selection: "; switch( getche() ) { // create specified employee type case 'm': arrap[n] = new manager; break; case 's': arrap[n] = new scientist; break; case 'l': arrap[n] = new laborer; break; default: cout << "\nUnknown employee type"; return; } arrap[n++]->getdata(); // get employee data from user } // display all employees void employee::display() { for(int j=0; j<n; j++) { cout << '\n' << (j+1); // display number switch( arrap[j]->get_type() ) // display type { case tmanager: cout << ". Type: Manager"; break; case tscientist: cout << ". Type: Scientist"; break; case tlaborer: cout << ". Type: Laborer"; break; default: cout << ". Unknown type"; return; } arrap[j]->putdata(); // display employee data } } // return the type of this object employee_type employee::get_type() { if( typeid(*this) == typeid(manager) ) return tmanager; else if( typeid(*this)==typeid(scientist) ) return tscientist; else if( typeid(*this)==typeid(laborer) ) return tlaborer; else { cout << "\nBad employee type"; exit(1); } return tmanager; } // write all current memory objects to file void employee::write() { int size; cout << "\nWriting " << n << " employees."; ofstream ouf; // open ofstream in binary employee_type etype; // type of each employee object ouf.open("EMPLOY.DAT", ios::trunc | ios::binary); if(!ouf) { cout << "\nCan't open file"; return; } for(int j=0; j<n; j++) // for every employee object { // get it's type etype = arrap[j]->get_type(); // write type to file ouf.write( (char*)&etype, sizeof(etype) ); switch(etype) // find its size { case tmanager: size=sizeof(manager); break; case tscientist: size=sizeof(scientist); break; case tlaborer: size=sizeof(laborer); break; } // write employee object to file ouf.write( (char*)(arrap[j]), size ); if(!ouf) { cout << "\nCan't write to file"; return; } } } // read data for all employees from file into memory void employee::read() { int size; // size of employee object employee_type etype; // type of employee ifstream inf; // open ifstream in binary inf.open("EMPLOY.DAT", ios::binary); if(!inf) { cout << "\nCan't open file"; return; } n = 0; // no employees in memory yet while(1) { // read type of next employee inf.read( (char*)&etype, sizeof(etype) ); if( inf.eof() ) // quit loop on eof break; if(!inf) // error reading type { cout << "\nCan't read type from file"; return; } switch(etype) { // make new employee case tmanager: // of correct type arrap[n] = new manager; size=sizeof(manager); break; case tscientist: arrap[n] = new scientist; size=sizeof(scientist); break; case tlaborer: arrap[n] = new laborer; size=sizeof(laborer); break; default: cout << "\nUnknown type in file"; return; } // read data from file into it inf.read( (char*)arrap[n], size ); if(!inf) // error but not eof { cout << "\nCan't read data from file"; return; } n++; // count employee } // end while cout << "\nReading " << n << " employees"; } // delete memory allocated for employees void employee::destroy() { for(int j=0; j<n; j++) delete arrap[j]; } void main() { while(1) { cout << "\n'a' -- add data for an employee" "\n'd' -- display data for all employees" "\n'w' -- write all employee data to file" "\n'r' -- read all employee data from file" "\n'x' -- exit" "\nType selection: "; switch( getche() ) { case 'a': // add an employee to list employee::add(); break; case 'd': // display all employees employee::display(); break; case 'w': // write employees to file employee::write(); break; case 'r': // read all employees from file employee::read(); break; case 'x': // exit program employee::destroy(); return; default: cout << "\nUnknown command"; } } // end while }
इस Program से हम समझ सकते हैं कि किस प्रकार से एक ऐसा Object जो कि Memory में हैं, हम उसकी Class का पता लगा सकते हैं। लेकिन File से Data को Read करते समय हमें ये पता कैसे चलेगा कि हम किस Class के Object का Data Read कर रहे हैं।
इसके लिए किसी प्रकार का कोई Function उपलब्ध नहीं हैं। जब हम एक Object के Data को File में Write करते हैं, तब हमें Object के Data के Just पहले Directly Disk पर एक Code लिखना होता है जो कि employee_type का एक enum Variable होता है, जो ये बताता है कि हमने किस Class के Data को Disk पर Write किया है।
यानी ये Code ही तय करता है कि हम किस प्रकार के Object का मान Disk पर Write कर रहे हैं। फिर जब हम Disk File से Object को फिर से Read करके Memory में Store करते हैं, तो हम Object के उस Code Number को Read करते हैं और Code के Type का एक नया Object Create करते हैं। अन्त में File से Object के Data को Read करके इस नए Object में Write कर देते हैं।
कई बार हमें किसी Object के Data को Object की शुरूआत से नहीं बल्कि कहीं भी बीच में से Read करने की जरूरत पड सकती है। जैसे char प्रकार का एक Array हो और फिर एक Object का Pointer Set करके इस Character प्रकार के Array को Read करवाया जाए। इसके लिए हम सम्भवतया निम्न Coding लिख सकते हैं:
char someArray[MAX]; // Object’s data is in this array aClass* aPtr_to_Obj; // Create Pointer aPtr_to_Obj = (aClass*)someArray; // Don’t do this
हालांकि char प्रकार का एक Array चाहे किसी Object के Data को ही Hold करके रखता हो, लेकिन वह स्वयं Object नहीं होता है। Array को Use करने की कोशिश करना या Array का Pointer Create करके इस तरह से Use करना जैसे कि ये किसी Object को Point करता हो, Problem Create कर सकता है। Object Create करने के केवल दो ही उचित तरीके हैं। या तो हम Object को Compile Time में Explicitly निम्नानुसार Define करें:
aClass anObj; // OK
या फिर निम्नानुसार Program के Runtime में new Operator का प्रयोग करके Implicitly Object को Memory Allocate करे।
aPtr_toObj = new aClass; // OK
जब हम किसी Object को उचित तरीके से Create करते हैं, तो उसका Constructor Invoke हो जाता है। ऐसा होता ही है चाहे हम Constructor Define करें या ना करें। यदि हम Constructor Define नहीं करते हैं तो Default Constructor Execute होता है।
Interaction with empl_io
पिछले Program से जब User Interaction करता है तो ये Interaction निम्नानुसार होता है, जिसमें User Memory में एक Manager, एक Scientist व एक Laborer Create करता है, उन्हें Disk पर Write करता है, Disk से Objects को Read करता है और उन्हें Screen पर Display करता है।
'a' -- add data for an employee 'd' -- display data for all employees 'w' -- write all employee data to file 'r' -- read all employee data from file 'x' -- exit Type selection: a 'm' to add a manager 's' to add a scientist 'l' to add a laborer Type selection: m Enter last name: Johnson Enter number: 1111 Enter title: President Enter golf club dues: 20000 'a' -- add data for an employee 'd' -- display data for all employees 'w' -- write all employee data to file 'r' -- read all employee data from file 'x' -- exit Type selection: a 'm' to add a manager 's' to add a scientist 'l' to add a laborer Type selection: s Enter last name: Faraday Enter number: 2222 Enter number of pubs: 99 'a' -- add data for an employee 'd' -- display data for all employees 'w' -- write all employee data to file 'r' -- read all employee data from file 'x' -- exit Type selection: a 'm' to add a manager 's' to add a scientist 'l' to add a laborer Type selection: l Enter last name: Smith Enter number: 3333 'a' -- add data for an employee 'd' -- display data for all employees 'w' -- write all employee data to file 'r' -- read all employee data from file 'x' -- exit Type selection: w Writing 3 employees 'a' -- add data for an employee 'd' -- display data for all employees 'w' -- write all employee data to file 'r' -- read all employee data from file 'x' -- exit Type selection: r Reading 3 employees 'a' -- add data for an employee 'd' -- display data for all employees 'w' -- write all employee data to file 'r' -- read all employee data from file 'x' -- exit Type selection: d 1. Type: Manager Name: Johnson Title: President Golf club dues: 20000 2. Type: Scientist Name: Faraday Number: 2222 Number of publications: 99 3. Type: Laborer Name: Smith Number: 3333
ये Article इस वेबसाईट पर Selling हेतु उपलब्ध EBook C++ Programming Language in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी।
C++ Programming Language in Hindi | Page: 666 | Format: PDF