സിയിലെ ഘടനകളെ എങ്ങനെ താരതമ്യം ചെയ്യാം. ഘടനകൾ. മാക്രോകളുടെ മുഴുവൻ വാചകം

C++ ഭാഷ ഒരു കോപ്പി കൺസ്ട്രക്റ്ററും ഒരു കോപ്പി അസൈൻമെൻ്റ് ഓപ്പറേറ്ററും ഡിഫോൾട്ടായി എല്ലാ ഉപയോക്തൃ-നിർവചിക്കപ്പെട്ട ക്ലാസുകൾക്കും ഘടനകൾക്കും സൃഷ്ടിക്കുന്നു. അതിനാൽ, പ്രധാനപ്പെട്ട നിരവധി കേസുകൾക്കായി, നിർദ്ദിഷ്ട ഫംഗ്ഷനുകൾ സ്വമേധയാ എഴുതുന്നതിൽ നിന്ന് പ്രോഗ്രാമർ സ്വതന്ത്രനാകുന്നു. ഉദാഹരണത്തിന്, ഡാറ്റ അടങ്ങിയ ഘടനകൾക്കായി ഡിഫോൾട്ട് ഓപ്പറേറ്റർമാർ നന്നായി പ്രവർത്തിക്കുന്നു. ഈ സാഹചര്യത്തിൽ, ലളിതമായ തരങ്ങളിലും std::vector അല്ലെങ്കിൽ std::string പോലുള്ള സങ്കീർണ്ണമായ പാത്രങ്ങളിലും ഡാറ്റ സംഭരിക്കാൻ കഴിയും.

ഇതിൻ്റെ വെളിച്ചത്തിൽ, സ്ഥിരസ്ഥിതിയായി == ഒപ്പം != സ്ട്രക്ചർ താരതമ്യ ഓപ്പറേറ്ററുകൾ ഉണ്ടായിരിക്കുന്നത് സൗകര്യപ്രദമായിരിക്കും, എന്നാൽ C++ കംപൈലർ, സ്റ്റാൻഡേർഡിന് അനുസൃതമായി, അവയെ സൃഷ്ടിക്കുന്നില്ല.

ഘടനകളുടെ അംഗീകൃത താരതമ്യത്തിനായി ഒരു ഓപ്പറേറ്റർ എഴുതുന്നത് ബുദ്ധിമുട്ടുള്ള കാര്യമല്ല, പക്ഷേ പ്രോഗ്രാമിൻ്റെ അത്തരം ഓർഗനൈസേഷൻ പിശകുകളുടെ വീക്ഷണകോണിൽ നിന്ന് അസൗകര്യവും അപകടകരവുമാണ്. ഉദാഹരണത്തിന്, ഒരു പ്രോഗ്രാമർ ഒരു ഘടനയിലേക്ക് ഒരു പുതിയ അംഗത്തെ ചേർക്കുന്നു, എന്നാൽ ഒരു ഇഷ്‌ടാനുസൃത താരതമ്യ ഓപ്പറേറ്ററിൽ അനുബന്ധ താരതമ്യം ചേർക്കാൻ മറന്നാൽ, പ്രോഗ്രാമിൽ പിശക് നിർണ്ണയിക്കാൻ വളരെ ബുദ്ധിമുട്ടാണ്. മാത്രമല്ല, ഘടനയുടെ പ്രഖ്യാപനവും ഉപയോക്തൃ താരതമ്യ ഓപ്പറേറ്ററും സാധാരണയായി പരസ്പരം വേർതിരിക്കപ്പെടുന്നു, കാരണം അവ വ്യത്യസ്ത ഫയലുകളിൽ (*.h, *.cpp) സ്ഥിതിചെയ്യുന്നു.

C++-നുള്ളിലെ അംഗീകൃത താരതമ്യ ഓപ്പറേറ്റർമാരുടെ എഴുത്ത് ഓട്ടോമേറ്റ് ചെയ്യുന്നത് എളുപ്പമല്ല, കാരണം പ്രോഗ്രാം നിർവ്വഹണ വേളയിൽ ഒരു ഘടനയിൽ എത്ര അംഗങ്ങളുണ്ടെന്നും ഏതൊക്കെ അംഗങ്ങളുണ്ടെന്നും കണ്ടെത്താൻ നിങ്ങളെ അനുവദിക്കുന്ന ഉപകരണങ്ങൾ ഈ ഭാഷയിലില്ല.

2000-കളുടെ മധ്യത്തിൽ, നിരന്തരം വികസിച്ചുകൊണ്ടിരിക്കുന്ന ഒരു വലിയ പ്രോജക്റ്റിൽ പ്രവർത്തിക്കുമ്പോൾ, ഡാറ്റാ ഘടനകളിൽ പതിവായി മാറ്റങ്ങൾ ആവശ്യമായി വരുമ്പോൾ, താരതമ്യ ഓപ്പറേറ്റർമാരുടെ പ്രശ്നം ഒരിക്കൽ കൂടി പരിഹരിക്കാൻ ഞാൻ തീരുമാനിച്ചു. തൽഫലമായി, മാക്രോകൾ ഉപയോഗിച്ച് C++ ൽ ഒരു നിർമ്മാണം സൃഷ്ടിച്ചു, ഇത് അംഗങ്ങൾ-അംഗങ്ങളുടെ താരതമ്യ ഓപ്പറേറ്റർമാരുടെ തുടർന്നുള്ള ഓട്ടോമാറ്റിക് ജനറേഷൻ ഉപയോഗിച്ച് ഘടനകൾ പ്രഖ്യാപിക്കുന്നത് സാധ്യമാക്കുന്നു. ഒരേ ഡിസൈൻ മറ്റ് അംഗങ്ങൾ-അംഗ പ്രവർത്തനങ്ങൾ സ്വയമേവ നടപ്പിലാക്കുന്നത് സാധ്യമാക്കി: ഫയലുകളിലേക്ക് ഡാറ്റ ലോഡ് ചെയ്യുകയും സംരക്ഷിക്കുകയും ചെയ്യുന്നു. ഞാൻ അത് നിങ്ങളുടെ ശ്രദ്ധയിൽപ്പെടുത്തുന്നു.

നിലവിലുള്ള മറ്റ് പരിഹാരങ്ങൾ

വിവരിച്ച പ്രശ്നത്തിനുള്ള ഇനിപ്പറയുന്ന ഇതര പരിഹാരങ്ങളെക്കുറിച്ച് ഇപ്പോൾ എനിക്കറിയാം:

  1. ചലനാത്മക ഘടനകൾ ഉപയോഗിക്കുന്നു. സാധാരണ C ++ ഘടനയ്ക്ക് പകരം, വൈവിധ്യമാർന്ന മൂലകങ്ങളുടെ ഒരു കണ്ടെയ്നർ ഉപയോഗിക്കുന്നു, അത് ഒരൊറ്റ തരത്തിലേക്ക് ചുരുക്കിയിരിക്കുന്നു. ഉദാഹരണത്തിന്, Windows OLE-ൽ നിന്നുള്ള VARIANT തരം. അംഗങ്ങളുടെ പേരുകൾ സംഭരിക്കുന്നതിന് ഇത് ഒരു സ്ട്രിംഗ് കണ്ടെയ്‌നറും ഉപയോഗിക്കുന്നു. ഇത് അംഗങ്ങളുടെ പേരുകൾ, തരങ്ങൾ, നമ്പറുകൾ എന്നിവ റൺടൈമിൽ പ്രോഗ്രാമിന് ലഭ്യമാക്കുന്നു. എന്നിരുന്നാലും, ഈ സമീപനം അത്തരം ഒരു ഘടനയിലെ അംഗങ്ങളെ ആക്സസ് ചെയ്യുന്നതിനുള്ള റൺടൈം ചെലവുകൾ അവതരിപ്പിക്കുന്നു. object.member_name അല്ലെങ്കിൽ pObject->member_name പോലെയുള്ള ആക്‌സസ് വാക്യഘടന ലഭ്യമല്ല, അത് object.at ("member_name") പോലെയുള്ള ഒന്നിലേക്ക് മാറ്റേണ്ടതുണ്ട്. കൂടാതെ, മെമ്മറി ഉപഭോഗത്തിൽ ഒരു രേഖീയ വർദ്ധനവ് ഉണ്ട്: ഘടനയുടെ ഓരോ സന്ദർഭവും ഒരു സാധാരണ (സ്റ്റാറ്റിക്) ഘടനയേക്കാൾ കൂടുതൽ മെമ്മറി സ്പേസ് എടുക്കുന്നു.
  2. ബൂസ്റ്റ് ലൈബ്രറി ഉപയോഗിക്കുന്നത്, അതായത് boost::fusion::map കണ്ടെയ്നർ. ഇവിടെ എല്ലാ ചെലവുകളും കംപൈലറിൻ്റെ ചുമലിൽ വയ്ക്കാൻ ഞങ്ങൾക്ക് കഴിഞ്ഞു, പക്ഷേ അംഗങ്ങളെ ആക്‌സസ് ചെയ്യുന്നതിനുള്ള പരമ്പരാഗത വാക്യഘടന സംരക്ഷിക്കാൻ കഴിഞ്ഞില്ല. നിങ്ങൾ ഇതുപോലുള്ള നിർമ്മാണങ്ങൾ ഉപയോഗിക്കേണ്ടതുണ്ട്: at_key (വസ്തു).
  3. C++ കോഡ് ജനറേഷൻ. C++ ലെ ഒരു ഘടനയുടെയും അതിൻ്റെ താരതമ്യ ഓപ്പറേറ്ററിൻ്റെയും വിവരണം പ്രോഗ്രാമർ സ്വമേധയാ എഴുതിയതല്ല, മറിച്ച് മറ്റേതെങ്കിലും ഇൻപുട്ട് ഭാഷയിലെ ഘടനയുടെ വിവരണത്തെ അടിസ്ഥാനമാക്കിയുള്ള ഒരു സ്ക്രിപ്റ്റ് ഉപയോഗിച്ചാണ് സൃഷ്ടിക്കുന്നത്. ഈ സമീപനം, എൻ്റെ കാഴ്ചപ്പാടിൽ, അനുയോജ്യമാണ്, എന്നാൽ ഇപ്പോൾ ഞാൻ അത് നടപ്പിലാക്കിയിട്ടില്ല, അതിനാൽ ഈ ലേഖനം അതിനെക്കുറിച്ചല്ല.
മാക്രോ അടിസ്ഥാനമാക്കിയുള്ള പരിഹാരം

മാക്രോകൾ ഉപയോഗിച്ച് എനിക്ക് നടപ്പിലാക്കാൻ കഴിഞ്ഞ പരിഹാരത്തിന് ഇനിപ്പറയുന്ന ഗുണങ്ങളുണ്ട്:

  • ഘടന അംഗങ്ങളെ ആക്‌സസ് ചെയ്യുന്നതിന് റൺടൈം ഓവർഹെഡ് ഇല്ല.
  • object.member_name അല്ലെങ്കിൽ pObject->member_name എന്ന ഫോമിൻ്റെ ഘടന അംഗങ്ങളെ ആക്‌സസ് ചെയ്യുന്നതിനുള്ള സ്റ്റാൻഡേർഡ് വാക്യഘടന സംരക്ഷിക്കാൻ സാധിച്ചു.
  • മെമ്മറി ലോഡ് O(1) ആണ്. മറ്റൊരു വിധത്തിൽ പറഞ്ഞാൽ, ഒരു യാന്ത്രിക താരതമ്യ ഘടനയുടെ ഓരോ സംഭവവും ഒരു സാധാരണ ഘടനയുടെ അതേ അളവിലുള്ള മെമ്മറി സ്പേസ് എടുക്കുന്നു. അത്തരം ഘടനകളുടെ ഓരോ പ്രഖ്യാപിത തരത്തിനും സ്ഥിരമായ (ചെറിയ) മെമ്മറി ചെലവ് മാത്രമേയുള്ളൂ.

പോരായ്മകളിൽ ഇനിപ്പറയുന്നവ ഉൾപ്പെടുന്നു:

  • ഇൻ്റലിസെൻസ് അല്ലെങ്കിൽ ഡോക്സിജെൻ പോലുള്ള വിശകലന ഉപകരണങ്ങളുടെ സൗകര്യം കുറയ്ക്കുന്ന ഘടനയിൽ അധിക സേവന അംഗങ്ങളുടെ സാന്നിധ്യം.
  • സേവന അംഗങ്ങളുടെയും ഉപയോക്താക്കളുടെയും പേരുകൾ തമ്മിൽ വൈരുദ്ധ്യമുണ്ടാകാനുള്ള സാധ്യത.
  • struct a = (1,2,3) പോലെയുള്ള ഇനീഷ്യലൈസറുകളുടെ ഒരു ലിസ്റ്റ് ഉപയോഗിച്ച് ആരംഭിക്കുന്നത് അസാധ്യമാണ്.
ഉപയോഗ ഉദാഹരണം

ഇനിപ്പറയുന്ന പതിവ് ഘടനയ്ക്ക് തുല്യമായ ആളുകളെക്കുറിച്ചുള്ള ഡാറ്റ സംഭരിക്കുന്നതിന് ഞങ്ങൾ ഒരു ഘടന സൃഷ്ടിക്കേണ്ടതുണ്ടെന്ന് കരുതുക:

Struct MANPARAMS ( std::string name; int age; std::vector സുഹൃത്തിൻ്റെ_പേരുകൾ; ഇരട്ട കർമ്മം; );

എൻ്റെ ലൈബ്രറിയെ അടിസ്ഥാനമാക്കി, സ്വയമേവ അംഗീകൃത പ്രവർത്തനങ്ങളുള്ള ഒരു ഘടന ഇതുപോലെ പ്രഖ്യാപിക്കപ്പെടുന്നു:

ക്ലാസ് AUTO_MANPARAMS ( PARAMSTRUCT_DECLARE_BEGIN(AUTO_MANPARAMS); പൊതുവായത്: DECLARE_MEMBER_PARAMSTRUCT(std::string, name); DECLARE_MEMBER_PARAMSTRUCT(int, age); DECLARE_MEMBER_PARAMS(sttor:veTRUCT_PARAMS , ചങ്ങാതി_പേരുകൾ); DECLARE_MEMBER_PARAMSTRUCT(ഇരട്ട, കർമ്മ); );

ഇതിനുശേഷം, മുഴുവൻ പ്രോഗ്രാമിനുമായി ഒരിക്കൽ, നിങ്ങൾ *.cpp ഫയലുകളിലൊന്നിൽ ഇനിപ്പറയുന്ന മാക്രോ കോൾ കംപൈൽ ചെയ്യേണ്ടതുണ്ട്:

PARAMFIELD_IMPL(AUTO_MANPARAMS);

എല്ലാം! ഇപ്പോൾ നിങ്ങൾക്ക് ഈ ഘടനകൾ സാധാരണ പോലെ സുരക്ഷിതമായി ഉപയോഗിക്കാനും, അനുബന്ധ ഓപ്പറേറ്റർമാരെ എഴുതുന്നതിനെക്കുറിച്ച് ആകുലപ്പെടാതെ, സമത്വത്തിനോ അസമത്വത്തിനോ വേണ്ടി താരതമ്യം ചെയ്യാം. ഉദാഹരണത്തിന്:

അസാധുവായ പുരുഷൻ(അസാധു) (AUTO_MANPARAMS man1, man2; man1.name = "John Smith"; man1.age = 18; man1.karma = 0; man2.name = "John Doe"; man2.age = 36; man2.karma = 1; man2.friends.push_back (“സെർഗുഡ് സ്മിത്ത്”); if(man1 == man2) printf (“Ku-ku!n”); )

നടപ്പിലാക്കൽ

മുകളിൽ പറഞ്ഞതിൽ നിന്ന് നിങ്ങൾക്ക് കാണാനാകുന്നതുപോലെ, ഓരോ ഘടനയുടെയും നിർവചനത്തിൻ്റെ തുടക്കത്തിൽ, നിങ്ങൾ മാക്രോ PARAMSTRUCT_DECLARE_BEGIN(x) എന്ന് വിളിക്കേണ്ടതുണ്ട്, അത് ആ ഘടനയ്‌ക്കായി ചില പൊതുവായ തരങ്ങളെയും സ്റ്റാറ്റിക് സേവന അംഗങ്ങളെയും നിർവചിക്കും. ഇതിനുശേഷം, ഓരോ ഉപയോക്തൃ അംഗത്തെയും പ്രഖ്യാപിക്കുമ്പോൾ, നിങ്ങൾ രണ്ടാമത്തെ മാക്രോ, DECLARE_MEMBER_PARAMSTRUCT(തരം, പേര്) എന്ന് വിളിക്കേണ്ടതുണ്ട്, ഇത് നിർദ്ദിഷ്ട പേരിനൊപ്പം അംഗത്തെ പ്രഖ്യാപിക്കുന്നതിനു പുറമേ, അതുമായി ബന്ധപ്പെട്ട ഘടനയിലെ സേവന അംഗങ്ങളെ നിർവചിക്കുന്നു.

നടപ്പിലാക്കുന്നതിനുള്ള അടിസ്ഥാന ആശയങ്ങൾ:

  • ഘടനയിലെ ഓരോ അംഗത്തിനും, ഈ അംഗത്തിനായുള്ള ഒരു താരതമ്യ പ്രവർത്തനം സ്വയമേവ ജനറേറ്റുചെയ്യുന്നു.
  • താരതമ്യ പ്രവർത്തനങ്ങളിലേക്കുള്ള പോയിൻ്ററുകൾ ഒരു സ്റ്റാറ്റിക് അറേയിൽ സംഭരിച്ചിരിക്കുന്നു. താരതമ്യ ഓപ്പറേറ്റർ ആ അറേയിലെ എല്ലാ ഘടകങ്ങളിലൂടെയും ലളിതമായി ആവർത്തിക്കുകയും ഓരോ അംഗത്തിനും ഒരു താരതമ്യ ഫംഗ്‌ഷൻ വിളിക്കുകയും ചെയ്യുന്നു.
  • പ്രോഗ്രാം ആരംഭിക്കുമ്പോൾ, ഘടനയിലെ അംഗങ്ങളെ പ്രഖ്യാപിക്കുന്നതിനുള്ള കോഡ് തനിപ്പകർപ്പാക്കാതിരിക്കാൻ ഈ അറേ ആരംഭിക്കുന്നു.
1. ഓരോ അംഗത്തിനും വേണ്ടിയുള്ള താരതമ്യ പ്രവർത്തനങ്ങളുടെ യാന്ത്രിക-ജനറേഷൻ

അത്തരം ഓരോ ഫംഗ്ഷനും ഘടനയിലെ അംഗമാണ് കൂടാതെ "അതിൻ്റെ" ഡാറ്റ അംഗത്തെ താരതമ്യം ചെയ്യുന്നു. ഇത് മാക്രോയിൽ DECLARE_MEMBER_PARAMSTRUCT(തരം, പേര്) ഇനിപ്പറയുന്ന രീതിയിൽ ജനറേറ്റ് ചെയ്യുന്നു:

Bool comp##name(const ThisParamFieldClass&a) const (മടങ്ങുന്ന പേര് == a.name; )

എവിടെയാണ് ThisParamFieldClass എന്നത് ഞങ്ങളുടെ ഘടനയുടെ തരമാണ്, അത് ഹെഡ് മാക്രോയിലെ ടൈപ്പ്‌ഡെഫ് വഴി പ്രഖ്യാപിക്കുന്നു - ചുവടെ കാണുക.

2. താരതമ്യ പ്രവർത്തനങ്ങൾക്കുള്ള പോയിൻ്ററുകളുള്ള അറേ

ഹെഡ് മാക്രോ PARAMSTRUCT_DECLARE_BEGIN(x) ഒരു സ്റ്റാറ്റിക് അറേ പ്രഖ്യാപിക്കുന്നു, അത് ഓരോ അംഗവും താരതമ്യ ഫംഗ്‌ഷനിലേക്ക് പോയിൻ്ററുകൾ സംഭരിക്കുന്നു. ഇത് ചെയ്യുന്നതിന്, ആദ്യം അവയുടെ തരം നിർണ്ണയിക്കുക:

#define PARAMSTRUCT_DECLARE_BEGIN(x) സ്വകാര്യം: typedef x ThisParamFieldClass; typedef bool (ThisParamFieldClass::*ComFun)(const ThisParamFieldClass& a) const; struct MEM_STAT_DATA (std::string member_name; ComFun comfun; );

തുടർന്ന് അറേ പ്രഖ്യാപിക്കുന്നു:

സ്റ്റാറ്റിക് എസ്ടിഡി:: വെക്റ്റർ സ്റ്റാറ്റ്_ഡാറ്റ;

താരതമ്യ ഓപ്പറേറ്റർമാരെയും ഇവിടെ പ്രഖ്യാപിച്ചിരിക്കുന്നു:

പൊതു: bool operator==(const ThisParamFieldClass& a) const; bool operator!=(const ThisParamFieldClass&a) const (റിട്ടേൺ !ഓപ്പറേറ്റർ==(a); )

മറ്റൊരു മാക്രോ (PARAMFIELD_IMPL) ആണ് താരതമ്യ ഓപ്പറേറ്റർ നടപ്പിലാക്കുന്നത്, എന്നാൽ നിങ്ങൾക്ക് ഒരു പൂരിപ്പിച്ച stat_data അറേ ഉണ്ടെങ്കിൽ അതിൻ്റെ നിർവ്വഹണം നിസ്സാരമാണ്: ഈ അറേയുടെ ഓരോ എലമെൻ്റിനുമുള്ള താരതമ്യ ഫംഗ്‌ഷനെ നിങ്ങൾ വിളിക്കേണ്ടതുണ്ട്.
ഘടനകളെ മാത്രം താരതമ്യം ചെയ്യാൻ, ഘടനയിലെ അംഗങ്ങളുടെ പേരുകൾ ഒരു ശ്രേണിയിൽ സൂക്ഷിക്കേണ്ട ആവശ്യമില്ല. എന്നിരുന്നാലും, പേരുകൾ സംഭരിക്കുന്നത്, മനുഷ്യർക്ക് വായിക്കാൻ കഴിയുന്ന ടെക്‌സ്‌റ്റ് ഫോർമാറ്റിൽ സംരക്ഷിക്കുന്നതും ലോഡുചെയ്യുന്നതും പോലുള്ള മറ്റ് പ്രവർത്തനങ്ങളുമായി താരതമ്യപ്പെടുത്തുമ്പോൾ അംഗങ്ങൾ-അംഗങ്ങളെ അപേക്ഷിച്ച് ആശയം വിപുലീകരിക്കാൻ അനുവദിക്കുന്നു.

3. ഘടന അംഗങ്ങളെക്കുറിച്ചുള്ള ഡാറ്റ പൂരിപ്പിക്കൽ

stat_data അറേ പൂരിപ്പിക്കുന്നതിനുള്ള പ്രശ്നം പരിഹരിക്കാൻ ഇത് ശേഷിക്കുന്നു. അംഗങ്ങളെക്കുറിച്ചുള്ള വിവരങ്ങൾ DECLARE_MEMBER_PARAMSTRUCT മാക്രോ ഒഴികെ മറ്റെവിടെയും ലഭ്യമല്ലാത്തതിനാൽ, അവിടെ നിന്ന് മാത്രമേ അറേ പൂരിപ്പിക്കാൻ കഴിയൂ (നേരിട്ടോ പരോക്ഷമായോ). എന്നിരുന്നാലും, ഈ മാക്രോയെ ഒരു സ്ട്രക്ചർ ഡിക്ലറേഷനിൽ വിളിക്കുന്നു, ഇത് ഒരു std:: vector ആരംഭിക്കുന്നതിനുള്ള ഏറ്റവും സൗകര്യപ്രദമായ സ്ഥലമല്ല. യൂട്ടിലിറ്റി ഒബ്ജക്റ്റുകൾ ഉപയോഗിച്ച് ഞാൻ ഈ പ്രശ്നം പരിഹരിച്ചു. ഘടനയിലെ ഓരോ അംഗത്തിനും, ഒരു സേവന ക്ലാസും ഈ ക്ലാസിൻ്റെ ഒരു വസ്തുവും പ്രഖ്യാപിക്കപ്പെടുന്നു. ഈ ക്ലാസിന് ഒരു കൺസ്ട്രക്റ്റർ ഉണ്ട് - ഇത് സ്റ്റാറ്റിക്ക് അറേ stat_data-യിലേക്ക് ഘടകത്തെക്കുറിച്ചുള്ള വിവരങ്ങൾ ചേർക്കുന്നു:

ക്ലാസ് cl##name (പൊതുവായത്: cl##name(void) ( if(populate_statdata) ( MEM_STAT_DATA msd = ( #name, &ThisParamFieldClass ::comp##name ); stat_data.push_back(msd); ) ); cl##പേര് ഒബ്##പേര്;

ഇവിടെ populate_statdata എന്നത് ഒരു സ്റ്റാറ്റിക് ഫ്ലാഗ് ആണ്, അത് ഹെഡ് മാക്രോയിൽ പ്രഖ്യാപിക്കുകയും stat_data അറേയിൽ ഘടനാ അംഗങ്ങളുടെ പേരുകളും അവയുടെ താരതമ്യ പ്രവർത്തനങ്ങളും ഉൾപ്പെടുത്തേണ്ടതുണ്ടോ എന്ന് സൂചിപ്പിക്കുന്നു. പ്രോഗ്രാം ആരംഭിക്കുമ്പോൾ, താഴെ വിവരിച്ചിരിക്കുന്ന ഇനീഷ്യലൈസേഷൻ മെക്കാനിസം populate_statdata=true സജ്ജമാക്കുകയും ഘടനയുടെ ഒരു ഉദാഹരണം സൃഷ്ടിക്കുകയും ചെയ്യുന്നു. ഈ സാഹചര്യത്തിൽ, ഘടനയിലെ ഓരോ അംഗവുമായും ബന്ധപ്പെട്ട സേവന ഒബ്ജക്റ്റുകളുടെ കൺസ്ട്രക്റ്റർമാർ അംഗങ്ങളെക്കുറിച്ചുള്ള ഡാറ്റ ഉപയോഗിച്ച് അറേ പൂരിപ്പിക്കുന്നു. ഇതിനുശേഷം, populate_statdata=false സജ്ജമാക്കി, അംഗവിവരങ്ങളുള്ള സ്റ്റാറ്റിക് അറേ ഇനി പരിഷ്‌ക്കരിക്കില്ല. ഓരോ തവണയും ഒരു ഉപയോക്തൃ പ്രോഗ്രാം ഒരു ഘടന സൃഷ്ടിക്കുമ്പോൾ, populate_statdata ഫ്ലാഗ് പരിശോധിക്കുമ്പോൾ, ഈ പരിഹാരം സമയം നഷ്ടപ്പെടുന്നതിലേക്ക് നയിക്കുന്നു. എന്നിരുന്നാലും, മെമ്മറി ഉപഭോഗം വർദ്ധിക്കുന്നില്ല: സേവന ഒബ്ജക്റ്റിൽ ഡാറ്റ അംഗങ്ങൾ അടങ്ങിയിട്ടില്ല, കൺസ്ട്രക്റ്റർ മാത്രം.

അവസാനമായി, populate_statdata നിയന്ത്രിക്കുന്നതിനുള്ള സംവിധാനം: ഒരു കൺസ്ട്രക്റ്ററുള്ള ഒരു സ്റ്റാറ്റിക് സർവീസ് ഒബ്‌ജക്റ്റ് ഉപയോഗിച്ചാണ് ഫ്ലാഗ് നടപ്പിലാക്കുന്നത്, മുഴുവൻ ഘടനയ്ക്കും ഒന്ന്. ഈ വസ്തു ഹെഡ് മാക്രോയിൽ പ്രഖ്യാപിച്ചിരിക്കുന്നു:

ക്ലാസ് VcfInitializer (പബ്ലിക്: VcfInitializer(അസാധു); ); സ്റ്റാറ്റിക് VcfInitializer vcinit;

കൺസ്‌ട്രക്‌ടറിൻ്റെ നടപ്പിലാക്കൽ മാക്രോ PARAMFIELD_IMPL(x):

X::VcfInitializer::VcfInitializer(അസാധു) ( x::populate_statdata = true; ThisParamFieldClass dummy; x::populate_statdata = false; )

മാക്രോകളുടെ മുഴുവൻ വാചകം
#define PARAMSTRUCT_DECLARE_BEGIN(x) സ്വകാര്യം: typedef x ThisParamFieldClass; typedef bool (ThisParamFieldClass::*ComFun)(const ThisParamFieldClass& a) const; struct MEM_STAT_DATA (std::string member_name; ComFun comfun; ); സ്റ്റാറ്റിക് എസ്ടിഡി:: വെക്റ്റർ സ്റ്റാറ്റ്_ഡാറ്റ; സ്റ്റാറ്റിക് ബൂൾ പോപ്പുലേറ്റ്_സ്റ്റാറ്റ്ഡാറ്റ; പൊതു: bool operator==(const ThisParamFieldClass& a) const; bool operator!=(const ThisParamFieldClass& a) const ( return ! operator==(a); ) private: class VcfInitializer (പൊതുവായത്: VcfInitializer(void); ); സ്റ്റാറ്റിക് VcfInitializer vcinit; #നിർവചിക്കുക DECLARE_MEMBER_PARAMSTRUCT(തരം, പേര്) പൊതുവായത്: ടൈപ്പ് പേര്; സ്വകാര്യം: bool comp##name(const ThisParamFieldClass&a) const (റിട്ടേൺ നെയിം == a.name; ) class cl##name ( public: cl##name(void) ( if(populate_statdata) ( MEM_STAT_DATA msd = ( #name , &ThisParamFieldClass::comp##name, );stat_data.push_back(msd); ) ); cl##പേര് ഒബ്##പേര്; #PARAMFIELD_IMPL(x) std::vector നിർവ്വചിക്കുക x::stat_data; bool x ::populate_statdata = false; x::VcfInitializer x::vcinit; x::VcfInitializer::VcfInitializer(void) ( x::populate_statdata = true; ThisParamFieldClass dummy; x::populate_statdata = false; ) bool x::operator==(const x&a) const (bool = true size_t i=0;r && i *stat_data[i].comfun)(a); ) റിട്ടേൺ r; )
ഉപസംഹാരം

മുകളിലുള്ള മാക്രോകളെ അടിസ്ഥാനമാക്കി, താരതമ്യ ഓപ്പറേറ്റർമാരും മറ്റ് അംഗങ്ങൾ അടിസ്ഥാനമാക്കിയുള്ള പ്രവർത്തനങ്ങളും സ്വയമേവ സൃഷ്‌ടിക്കുന്ന ഘടനകൾ നിങ്ങൾക്ക് പ്രഖ്യാപിക്കാനാകും. അത്തരം മറ്റ് പ്രവർത്തനങ്ങളിൽ ഉൾപ്പെടുന്നു, ഉദാഹരണത്തിന്, XML ഫോർമാറ്റിലുള്ള ടെക്സ്റ്റ് ഫയലുകൾ ലോഡുചെയ്യുന്നതും സംരക്ഷിക്കുന്നതും. കോഡ് ഡ്യൂപ്ലിക്കേഷൻ്റെ അഭാവം ജോലി എളുപ്പമാക്കുകയും പിശകുകൾ തടയുകയും ചെയ്യുന്നു. ഒരു സ്ട്രക്ചർ അംഗത്തെ പ്രഖ്യാപിക്കുന്നത്, ഓപ്പറേഷനുകൾ താരതമ്യം ചെയ്യാനും സംരക്ഷിക്കാനും ലോഡ് ചെയ്യാനും ആ അംഗത്തെ ചേർക്കുന്നു.

ഘടനകൾ

നിങ്ങൾക്ക് ഇതിനകം അറിയാവുന്നതുപോലെ, ക്ലാസുകൾ റഫറൻസ് ഡാറ്റ തരങ്ങളാണ്. ഇതിനർത്ഥം നേരിട്ട് ആക്‌സസ് ചെയ്യാവുന്ന ലളിതമായ തരങ്ങളുടെ മൂല്യങ്ങളിൽ നിന്ന് വ്യത്യസ്തമായി ഒരു പ്രത്യേക ക്ലാസിലെ ഒബ്‌ജക്റ്റുകൾ റഫറൻസ് വഴി ആക്‌സസ് ചെയ്യാനാകുമെന്നാണ്. എന്നാൽ ചിലപ്പോൾ ലളിതമായ തരങ്ങളുടെ മൂല്യങ്ങളായി ഒബ്‌ജക്റ്റുകളിലേക്കുള്ള നേരിട്ടുള്ള ആക്‌സസ് ഉപയോഗപ്രദമാകും, ഉദാഹരണത്തിന്, പ്രോഗ്രാം കാര്യക്ഷമത വർദ്ധിപ്പിക്കുന്നതിന്. എല്ലാത്തിനുമുപരി, റഫറൻസ് വഴിയുള്ള ഒബ്‌ജക്റ്റുകളിലേക്കുള്ള (ഏറ്റവും ചെറിയവ പോലും) എല്ലാ ആക്‌സസ്സും കമ്പ്യൂട്ടിംഗ് ഉറവിടങ്ങളുടെയും റാമിൻ്റെയും ഉപഭോഗത്തിനായുള്ള അധിക ചിലവുകളുമായി ബന്ധപ്പെട്ടിരിക്കുന്നു.

അത്തരം ബുദ്ധിമുട്ടുകൾ പരിഹരിക്കുന്നതിന്, C# നൽകുന്നു ഘടന, ഇത് ഒരു ക്ലാസിന് സമാനമാണ് എന്നാൽ ഒരു റഫറൻസ് ഡാറ്റ തരത്തേക്കാൾ മൂല്യ തരമാണ്. ആ. സ്‌ട്രക്‌റ്റുകൾ മെമ്മറിയിൽ എങ്ങനെ സംഭരിക്കുന്നു, അവ എങ്ങനെ ആക്‌സസ് ചെയ്യുന്നു (ക്ലാസുകൾ കൂമ്പാരത്തിൽ അനുവദിച്ചിരിക്കുന്ന റഫറൻസ് തരങ്ങളാണ്, സ്‌ട്രക്‌റ്റുകൾ സ്റ്റാക്കിൽ അനുവദിച്ചിരിക്കുന്ന മൂല്യ തരങ്ങളാണ്), കൂടാതെ ചില പ്രോപ്പർട്ടികൾ (ഉദാഹരണത്തിന്, സ്ട്രക്‌റ്റുകൾ പാരമ്പര്യത്തെ പിന്തുണയ്ക്കുന്നില്ല. ) പ്രകടന കാരണങ്ങളാൽ, ചെറിയ ഡാറ്റ തരങ്ങൾക്കായി നിങ്ങൾ ഘടനകൾ ഉപയോഗിക്കും. എന്നിരുന്നാലും, വാക്യഘടനയുടെ കാര്യത്തിൽ, ഘടനകൾ ക്ലാസുകളുമായി വളരെ സാമ്യമുള്ളതാണ്.

പ്രധാന വ്യത്യാസം അവ ഉപയോഗിച്ച് പ്രഖ്യാപിക്കപ്പെടുന്നു എന്നതാണ് struct കീവേഡ്ക്ലാസ്സിന് പകരം. ഒരു ഘടനാ പ്രഖ്യാപനത്തിൻ്റെ പൊതുവായ രൂപമാണ് ഇനിപ്പറയുന്നത്:

ഘടനയുടെ പേര്: ഇൻ്റർഫേസുകൾ ( // അംഗ പ്രഖ്യാപനങ്ങൾ )

ഇവിടെ പേര് ഘടനയുടെ നിർദ്ദിഷ്ട നാമത്തെ സൂചിപ്പിക്കുന്നു.

ക്ലാസുകൾ പോലെ, ഓരോ ഘടനയ്ക്കും അതിൻ്റേതായ അംഗങ്ങളുണ്ട്: രീതികൾ, ഫീൽഡുകൾ, സൂചികകൾ, പ്രോപ്പർട്ടികൾ, ഓപ്പറേറ്റർ രീതികൾ, ഇവൻ്റുകൾ. ഘടനകൾക്ക് കൺസ്ട്രക്റ്ററുകളെ നിർവചിക്കാനാകും, പക്ഷേ ഡിസ്ട്രക്റ്ററുകളല്ല. എന്നിരുന്നാലും, ഒരു ഘടനയ്ക്കായി നിങ്ങൾക്ക് ഒരു ഡിഫോൾട്ട് കൺസ്ട്രക്റ്റർ നിർവചിക്കാൻ കഴിയില്ല (അതായത്, പാരാമീറ്ററുകളില്ലാത്ത ഒരു കൺസ്ട്രക്റ്റർ). ഡിഫോൾട്ട് കൺസ്ട്രക്റ്റർ എല്ലാ ഘടനകൾക്കും സ്വയമേവ നിർണ്ണയിക്കപ്പെടുന്നു, അത് മാറ്റാൻ കഴിയില്ല എന്നതാണ്. ഈ കൺസ്ട്രക്റ്റർ സ്ഥിരസ്ഥിതി മൂല്യങ്ങൾ ഉപയോഗിച്ച് ഘടനയുടെ ഫീൽഡുകൾ ആരംഭിക്കുന്നു. ഘടനകൾ അനന്തരാവകാശത്തെ പിന്തുണയ്ക്കാത്തതിനാൽ, അവയുടെ അംഗങ്ങളെ അമൂർത്തമോ വെർച്വൽ അല്ലെങ്കിൽ പരിരക്ഷിതമോ ആയി വ്യക്തമാക്കാൻ കഴിയില്ല.

ഉപയോഗിച്ച് ഒരു ഘടനാപരമായ ഒബ്ജക്റ്റ് സൃഷ്ടിക്കാൻ കഴിയും ഓപ്പറേറ്റർ പുതിയത്ഒരു ക്ലാസ് ഒബ്ജക്റ്റ് പോലെ തന്നെ, എന്നാൽ ഇത് പ്രത്യേകിച്ച് ആവശ്യമില്ല. എല്ലാത്തിനുമുപരി, പുതിയ ഓപ്പറേറ്റർ ഉപയോഗിക്കുമ്പോൾ, സ്ഥിരസ്ഥിതി കൺസ്ട്രക്റ്റർ വിളിക്കപ്പെടുന്നു. ഈ ഓപ്പറേറ്റർ ഉപയോഗിക്കാത്തപ്പോൾ, ഒബ്ജക്റ്റ് ഇപ്പോഴും സൃഷ്ടിക്കപ്പെടുന്നു, അത് ആരംഭിച്ചിട്ടില്ലെങ്കിലും. ഈ സാഹചര്യത്തിൽ, ഘടനയിലെ ഏതെങ്കിലും അംഗങ്ങൾ സ്വമേധയാ ആരംഭിക്കേണ്ടതുണ്ട്.

ഘടനകൾ ഉപയോഗിക്കുന്നതിനുള്ള ഒരു ഉദാഹരണം നോക്കാം:

സിസ്റ്റം ഉപയോഗിക്കുന്നു; namespace ConsoleApplication1 ( // ഒരു ഘടന ഘടന സൃഷ്‌ടിക്കുക UserInfo (പൊതു സ്ട്രിംഗ് നാമം; പൊതു ബൈറ്റ് പ്രായം; പൊതു ഉപയോക്തൃ ഇൻഫോ (സ്ട്രിംഗ് നാമം, ബൈറ്റ് പ്രായം) ( this.Name = പേര്; ഈ. വയസ്സ് = പ്രായം; ) പൊതു ശൂന്യമായ WriteUserInfo() ( കൺസോൾ. WriteLine ("പേര്: (0), വയസ്സ്: (1)", പേര്, വയസ്സ്); ) ) ക്ലാസ് പ്രോഗ്രാം ( സ്റ്റാറ്റിക് ശൂന്യമായ മെയിൻ() ( UserInfo user1 = new UserInfo("Alexandr", 26); Console.Write(" user1 : "); user1.WriteUserInfo(); UserInfo user2 = new UserInfo("Elena",22); Console.Write("user2: "); user2.WriteUserInfo(); // ഘടനകളും ക്ലാസുകളും തമ്മിലുള്ള പ്രധാന വ്യത്യാസം കാണിക്കുക user1 = user2 ; user2.Name = "Natalya"; user2.Age = 25; Console.Write("\nuser1: "); user1.WriteUserInfo(); Console.Write("user2:"); user2.WriteUserInfo() ; കൺസോൾ. ReadLine(); ) )

ഒരു ഘടന മറ്റൊന്നിലേക്ക് നിയോഗിക്കുമ്പോൾ, അതിൻ്റെ ഒബ്ജക്റ്റിൻ്റെ ഒരു പകർപ്പ് സൃഷ്ടിക്കപ്പെടുന്നു എന്നത് ശ്രദ്ധിക്കുക. ഒരു ഘടനയും ക്ലാസും തമ്മിലുള്ള പ്രധാന വ്യത്യാസങ്ങളിൽ ഒന്നാണിത്. ഒരു ക്ലാസിലേക്കുള്ള ഒരു റഫറൻസ് മറ്റൊരു ക്ലാസിലേക്കുള്ള റഫറൻസിനായി അസൈൻ ചെയ്യപ്പെടുമ്പോൾ, അസൈൻമെൻ്റ് സ്റ്റേറ്റ്‌മെൻ്റിൻ്റെ ഇടതുവശത്തുള്ള റഫറൻസ് വലതുവശത്തുള്ള റഫറൻസിൻ്റെ അതേ ഒബ്‌ജക്റ്റിലേക്ക് പോയിൻ്റ് ചെയ്യുന്നു എന്നതാണ് ഫലം. ഒരു ഘടനയിലെ ഒരു വേരിയബിൾ മറ്റൊരു ഘടനയിലെ ഒരു വേരിയബിളിലേക്ക് അസൈൻ ചെയ്യുമ്പോൾ, അസൈൻമെൻ്റ് സ്റ്റേറ്റ്‌മെൻ്റിൻ്റെ വലതുവശത്തുള്ള ഘടന ഒബ്‌ജക്റ്റിൻ്റെ ഒരു പകർപ്പ് സൃഷ്ടിക്കപ്പെടുന്നു.

അതിനാൽ, മുമ്പത്തെ ഉദാഹരണം ഒരു സ്ട്രക്റ്റിന് പകരം UserInfo ക്ലാസ് ഉപയോഗിച്ചിരുന്നെങ്കിൽ, ഇനിപ്പറയുന്ന ഫലം ഉണ്ടാകുമായിരുന്നു:

ഘടനകളുടെ ഉദ്ദേശ്യം

മേൽപ്പറഞ്ഞവയുമായി ബന്ധപ്പെട്ട്, ന്യായമായ ഒരു ചോദ്യം ഉയർന്നുവരുന്നു: ഒരു ക്ലാസിനേക്കാൾ കൂടുതൽ മിതമായ കഴിവുകളുണ്ടെങ്കിൽ ഒരു ഘടന സി#-ൽ ഉൾപ്പെടുത്തിയിരിക്കുന്നത് എന്തുകൊണ്ട്? പ്രോഗ്രാമുകളുടെ കാര്യക്ഷമതയും ഉൽപ്പാദനക്ഷമതയും മെച്ചപ്പെടുത്തുന്നതിലാണ് ഈ ചോദ്യത്തിനുള്ള ഉത്തരം. ഘടനകൾ മൂല്യ തരങ്ങളാണ്, അതിനാൽ അവ റഫറൻസ് വഴിയല്ല നേരിട്ട് കൈകാര്യം ചെയ്യാൻ കഴിയും. തൽഫലമായി, ഘടനയുമായി പ്രവർത്തിക്കാൻ, ഒരു റഫറൻസ് തരത്തിൻ്റെ ഒരു വേരിയബിൾ ആവശ്യമില്ല, ചില സന്ദർഭങ്ങളിൽ, റാമിൽ കാര്യമായ ലാഭം എന്നാണ് ഇതിനർത്ഥം.