Size of Derived Objects

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
Smart Object and Class
Shift Operators Overloading

CPP Programming Language in Hindiये Article इस वेबसाईट पर Selling हेतु उपलब्‍ध EBook C++ Programming Language in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी। 

C++ Programming Language in Hindi | Page: 666 | Format: PDF

BUY NOW GET DEMO REVIEWS