C ++ में सुरक्षित इंटरफ़ेस के लिए पैटर्न क्या है


22

नोट: निम्नलिखित C ++ 03 कोड है, लेकिन हमें अगले दो वर्षों में C ++ 11 के लिए एक कदम की उम्मीद है, इसलिए हमें इसे ध्यान में रखना चाहिए।

C ++ में अमूर्त इंटरफ़ेस लिखने के तरीके के बारे में (अन्य लोगों के बीच) के लिए एक दिशानिर्देश लिख रहा हूं। मैंने इस विषय पर सटर के दोनों लेख पढ़े हैं, उदाहरणों और उत्तरों के लिए इंटरनेट पर खोज की, और कुछ परीक्षण किए।

इस कोड को संकलित नहीं करना चाहिए!

void foo(SomeInterface & a, SomeInterface & b)
{
   SomeInterface c ;               // must not be default-constructible
   SomeInterface d(a);             // must not be copy-constructible
   a = b ;                         // must not be assignable
}

उपरोक्त सभी व्यवहार स्लाइसिंग में उनकी समस्या के स्रोत का पता लगाते हैं : सार इंटरफ़ेस (या पदानुक्रम में गैर-पत्ती वर्ग) रचनात्मक नहीं होना चाहिए और न ही मैथुन योग्य / असाइन किया जाना चाहिए, यदि व्युत्पन्न वर्ग हो सकता है।

0 समाधान: बुनियादी इंटरफ़ेस

class VirtuallyDestructible
{
   public :
      virtual ~VirtuallyDestructible() {}
} ;

यह समाधान सादा है, और कुछ हद तक भोला है: यह हमारे सभी अवरोधों को विफल करता है: यह डिफ़ॉल्ट रूप से निर्मित, कॉपी-निर्माण और कॉपी-असाइन किया जा सकता है (मैं कदम बिल्डरों और असाइनमेंट के बारे में निश्चित नहीं हूं, लेकिन मुझे अभी भी 2 साल का समय है यह बाहर)।

  1. हम विध्वंसक को शुद्ध आभासी घोषित नहीं कर सकते क्योंकि हमें इसे इनलाइन रखने की आवश्यकता है, और हमारे कुछ संकलक इनलाइन खाली शरीर के साथ शुद्ध आभासी तरीकों को पचा नहीं पाएंगे।
  2. हां, इस वर्ग का एकमात्र उद्देश्य कार्यान्वयनकर्ताओं को लगभग विनाशकारी बनाना है, जो एक दुर्लभ मामला है।
  3. यहां तक ​​कि अगर हमारे पास एक अतिरिक्त आभासी शुद्ध विधि है (जो कि अधिकांश मामलों में है), तो यह वर्ग अभी भी कॉपी-असाइन किया जाएगा।

तो, नहीं ...

पहला समाधान: बढ़ावा :: नॉनकॉपीबल

class VirtuallyDestructible : boost::noncopyable
{
   public :
      virtual ~VirtuallyDestructible() {}
} ;

यह समाधान सबसे अच्छा है, क्योंकि यह स्पष्ट है, स्पष्ट है, और C ++ (कोई मैक्रो)

समस्या यह है कि यह अभी भी उस विशिष्ट इंटरफ़ेस के लिए काम नहीं करता है क्योंकि वस्तुतःConstructible अभी भी डिफ़ॉल्ट रूप से निर्मित किया जा सकता है

  1. हम विध्वंसक को शुद्ध आभासी घोषित नहीं कर सकते क्योंकि हमें इसे इनलाइन रखने की आवश्यकता है, और हमारे कुछ संकलक इसे पचा नहीं पाएंगे।
  2. हां, इस वर्ग का एकमात्र उद्देश्य कार्यान्वयनकर्ताओं को लगभग विनाशकारी बनाना है, जो एक दुर्लभ मामला है।

एक और समस्या यह है कि गैर-प्रतिलिपि योग्य इंटरफ़ेस को लागू करने वाली कक्षाओं को तब कॉपी कंस्ट्रक्टर और असाइनमेंट ऑपरेटर को स्पष्ट रूप से घोषित / परिभाषित करना होगा यदि उन्हें उन तरीकों की आवश्यकता है (और हमारे कोड में, हमारे पास मूल्य वर्ग हैं जो अभी भी हमारे क्लाइंट द्वारा एक्सेस किए जा सकते हैं इंटरफेस)।

यह शून्य के नियम के खिलाफ जाता है, जहां हम जाना चाहते हैं: यदि डिफ़ॉल्ट कार्यान्वयन ठीक है, तो हमें इसका उपयोग करने में सक्षम होना चाहिए।

दूसरा समाधान: उन्हें संरक्षित करें!

class MyInterface
{
   public :
      virtual ~MyInterface() {}

   protected :
      // With C++11, these methods would be "= default"
      MyInterface() {}
      MyInterface(const MyInterface & ) {}
      MyInterface & operator = (const MyInterface & ) { return *this ; }
} ;

यह पैटर्न हमारे पास मौजूद तकनीकी बाधाओं (कम से कम उपयोगकर्ता कोड में) का अनुसरण करता है : MyInterface डिफ़ॉल्ट रूप से निर्मित नहीं किया जा सकता है, कॉपी-निर्माण नहीं किया जा सकता है और कॉपी-असाइन नहीं किया जा सकता है।

इसके अलावा, यह कक्षाओं को लागू करने में कोई कृत्रिम बाधा नहीं डालता है , जो तब शून्य के नियम का पालन करने के लिए स्वतंत्र हैं, या यहां तक ​​कि कुछ बिल्डरों / ऑपरेटरों को बिना समस्या के C ++ 11/14 में "= डिफ़ॉल्ट" घोषित करते हैं।

अब, यह काफी क्रियात्मक है, और एक विकल्प एक मैक्रो का उपयोग करना होगा, कुछ इस तरह से:

class MyInterface
{
   public :
      virtual ~MyInterface() {}

   protected :
      DECLARE_AS_NON_SLICEABLE(MyInterface) ;
} ;

संरक्षित मैक्रो के बाहर रहना चाहिए (क्योंकि इसमें कोई गुंजाइश नहीं है)।

सही ढंग से "नामस्थान" (जो आपकी कंपनी या उत्पाद के नाम के साथ उपसर्ग है), मैक्रो हानिरहित होना चाहिए।

और लाभ यह है कि कोड को सभी स्रोतों में कॉपी किए जाने के बजाय एक स्रोत में विभाजित किया गया है। क्या चाल-निर्माण और चाल-असाइनमेंट को भविष्य में उसी तरह स्पष्ट रूप से अक्षम किया जाना चाहिए, यह कोड में बहुत हल्का परिवर्तन होगा।

निष्कर्ष

  • क्या मैं चाहता हूं कि इंटरफेस में स्लाइसिंग के खिलाफ कोड को संरक्षित किया जाए? (मेरा मानना ​​है कि मैं नहीं हूँ, लेकिन एक कभी नहीं जानता ...)
  • उपरोक्त लोगों में सबसे अच्छा समाधान क्या है?
  • क्या कोई दूसरा, बेहतर उपाय है?

कृपया याद रखें कि यह एक ऐसा पैटर्न है जो न्यूबरी (दूसरों के बीच) के लिए एक दिशानिर्देश के रूप में काम करेगा, इसलिए एक समाधान जैसे: "प्रत्येक मामले में इसका कार्यान्वयन होना चाहिए" एक व्यवहार्य समाधान नहीं है।

बाउंटी और परिणाम

प्रश्नों के उत्तर देने के लिए समय व्यतीत करने और उत्तरों की प्रासंगिकता के कारण मैंने इनाम को कोरडंप को प्रदान किया ।

समस्या का मेरा समाधान शायद कुछ इस तरह से होगा:

class MyInterface
{
   DECLARE_CLASS_AS_INTERFACE(MyInterface) ;

   public :
      // the virtual methods
} ;

... निम्नलिखित मैक्रो के साथ:

#define DECLARE_CLASS_AS_INTERFACE(ClassName)                                \
   public :                                                                  \
      virtual ~ClassName() {}                                                \
   protected :                                                               \
      ClassName() {}                                                         \
      ClassName(const ClassName & ) {}                                       \
      ClassName & operator = (const ClassName & ) { return *this ; }         \
   private :

यह निम्नलिखित कारणों से मेरी समस्या का एक व्यवहार्य समाधान है:

  • इस वर्ग को तत्काल नहीं बनाया जा सकता है (निर्माणकर्ता संरक्षित हैं)
  • यह वर्ग वस्तुतः नष्ट हो सकता है
  • इस वर्ग को विरासत की कक्षाओं पर अनुचित बाधाएं लादे बिना विरासत में लिया जा सकता है (जैसे विरासत वर्ग डिफ़ॉल्ट मैथुन योग्य हो सकता है)
  • मैक्रो के उपयोग का अर्थ है कि इंटरफ़ेस "घोषणा" आसानी से पहचाने जाने योग्य (और खोज योग्य) है, और इसके कोड को एक जगह पर फैक्टर किया जाता है जिससे इसे संशोधित करना आसान हो जाता है (एक उपयुक्त उपसर्ग नाम अवांछनीय नाम झड़पों को हटा देगा)

ध्यान दें कि अन्य उत्तरों ने बहुमूल्य अंतर्दृष्टि दी। आप सभी को धन्यवाद जिन्होंने इसे शॉट दिया।

ध्यान दें कि मुझे लगता है कि मैं अभी भी इस सवाल पर एक और इनाम रख सकता हूं, और मैं पर्याप्त जवाब देता हूं जो मुझे देखना चाहिए, मैं उस जवाब को देने के लिए एक इनाम खोलूंगा।


5
क्या आप इंटरफ़ेस में केवल शुद्ध आभासी कार्यों का उपयोग नहीं कर सकते हैं? virtual void bar() = 0;उदाहरण के लिए? जो आपके इंटरफ़ेस को इंस्टेंश होने से रोकेगा।
मोरवेन

@ मॉरवेन: जैसा कि प्रश्न में कहा गया है, इससे 99% मामलों का समाधान होगा (यदि संभव हो तो मैं 100% का लक्ष्य रखता हूं)। यहां तक ​​कि अगर हम लापता 1% को अनदेखा करना चुनते हैं, तो भी यह असाइनमेंट टुकड़ा करने की क्रिया को हल नहीं करेगा। तो, नहीं, यह एक अच्छा समाधान नहीं है।
पियरसबल

@ मॉरवेन: गंभीरता से! ...: - डी ... मैंने पहली बार स्टैकऑवरफ्लो पर यह प्रश्न लिखा था, और फिर इसे सबमिट करने से ठीक पहले अपना विचार बदल दिया। क्या आप मानते हैं कि मुझे इसे यहां हटा देना चाहिए, और इसे एसओ को सौंप देना चाहिए।
पियरसबल

अगर मैं सही हूं तो आपको केवल virtual ~VirtuallyDestructible() = 0इंटरफ़ेस कक्षाओं (सार सदस्यों के साथ) की आभासी विरासत चाहिए। आप संभावना है कि वस्तुतःDestructible छोड़ सकते हैं।
डाइटर लुक्किंग

5
@paercebal: यदि कंपाइलर शुद्ध आभासी कक्षाओं में चोक करता है तो यह कूड़ेदान में आता है। एक वास्तविक इंटरफ़ेस परिभाषा शुद्ध आभासी द्वारा है।
कोई

जवाबों:


13

C ++ में इंटरफ़ेस बनाने का विहित तरीका यह है कि इसे एक शुद्ध वर्चुअल डिस्ट्रक्टर दिया जाए। यह सुनिश्चित करता है

  • इंटरफ़ेस वर्ग का कोई उदाहरण स्वयं नहीं बनाया जा सकता है, क्योंकि C ++ आपको एक अमूर्त वर्ग का उदाहरण बनाने की अनुमति नहीं देता है। यह निर्माण योग्य आवश्यकताओं (डिफ़ॉल्ट और प्रतिलिपि दोनों) का ध्यान रखता है।
  • deleteइंटरफ़ेस को एक पॉइंटर पर कॉल करना सही काम करता है: यह उस उदाहरण के लिए सबसे व्युत्पन्न वर्ग के विनाशकर्ता को बुलाता है।

बस एक शुद्ध वर्चुअल डिस्ट्रक्टर होने से इंटरफ़ेस के संदर्भ में असाइनमेंट को रोका नहीं जा सकता है। अगर आपको जरूरत है कि आप भी असफल हो जाएं, तो आपको अपने इंटरफेस में एक संरक्षित असाइनमेंट ऑपरेटर जोड़ना होगा।

कोई भी C ++ कंपाइलर इस तरह एक वर्ग / इंटरफ़ेस को संभालने में सक्षम होना चाहिए (सभी एक हेडर फ़ाइल में):

class MyInterface {
public:
  virtual ~MyInterface() = 0;
protected:
  MyInterface& operator=(const MyInterface&) { return *this; } // or = default for C++14
};

inline MyInterface::~MyInterface() {}

यदि आपके पास एक कंपाइलर है जो इस पर चुटकुले देता है (जिसका अर्थ है कि यह प्री-सी ++ 98 होना चाहिए), तो आपका विकल्प 2 (संरक्षित कंस्ट्रक्टर वाले) एक अच्छा दूसरा-सबसे अच्छा है।

boost::noncopyableइस कार्य के लिए उपयोग करना उचित नहीं है, क्योंकि यह संदेश देता है कि पदानुक्रम में सभी कक्षाएं गैर-प्रतिलिपि योग्य होनी चाहिए और इस प्रकार यह अधिक अनुभवी डेवलपर्स के लिए भ्रम पैदा कर सकता है जो इस तरह से इसका उपयोग करने के लिए आपके इरादों से परिचित नहीं होंगे।


If you need [prevent assignment] to fail as well, then you must add a protected assignment operator to your interface.: यही मेरी समस्या की जड़ है। जिन मामलों में मुझे असाइनमेंट का समर्थन करने के लिए इंटरफ़ेस की आवश्यकता है, वे वास्तव में दुर्लभ होने चाहिए। दूसरी ओर, वे मामले जहां मैं संदर्भ द्वारा एक इंटरफ़ेस पास करना चाहता हूं (ऐसे मामले जहां NULL स्वीकार्य नहीं है), और इस प्रकार, संकलित न होने वाले या स्लाइसिंग से बचना चाहते हैं।
पियरसबल

जैसा कि असाइनमेंट-ऑपरेटर को कभी नहीं बुलाया जाना चाहिए, आप इसे एक परिभाषा क्यों देते हैं? एक तरफ के रूप में, यह क्यों नहीं private? इसके अलावा, आप डिफ़ॉल्ट- और कॉपी-कोटर से निपटना चाह सकते हैं।
Deduplicator

5

क्या मैं पागल हूँ ...

  • क्या मैं चाहता हूं कि इंटरफेस में स्लाइसिंग के खिलाफ कोड को संरक्षित किया जाए? (मेरा मानना ​​है कि मैं नहीं हूँ, लेकिन एक कभी नहीं जानता ...)

क्या यह जोखिम प्रबंधन का मुद्दा नहीं है?

  • क्या आपको डर है कि टुकड़ा करने की क्रिया से संबंधित बग को पेश किया जा सकता है?
  • क्या आपको लगता है कि यह किसी का ध्यान नहीं जा सकता है और अपरिवर्तनीय बग को उत्तेजित कर सकता है?
  • स्लाइसिंग से बचने के लिए आप किस हद तक जाने को तैयार हैं?

सबसे अच्छा उपाय

  • उपरोक्त लोगों में सबसे अच्छा समाधान क्या है?

आपका दूसरा समाधान ("उन्हें संरक्षित करें") अच्छा लग रहा है, लेकिन ध्यान रखें कि मैं सी ++ विशेषज्ञ नहीं हूं।
कम से कम, अमान्य usages को मेरे संकलक (जी ++) द्वारा गलत तरीके से बताया गया है।

अब, क्या आपको मैक्रोज़ की आवश्यकता है? मैं "हाँ" कहूँगा, क्योंकि भले ही आप यह न कहें कि आप जो दिशानिर्देश लिख रहे हैं, उसका उद्देश्य क्या है, मुझे लगता है कि यह आपके उत्पाद के कोड में सर्वोत्तम प्रथाओं के एक विशेष सेट को लागू करने के लिए है।

उस उद्देश्य के लिए, मैक्रोज़ यह पता लगाने में मदद कर सकते हैं कि लोग प्रभावी रूप से पैटर्न कब लागू करते हैं: कमिट्स का एक मूल फ़िल्टर आपको बता सकता है कि क्या मैक्रो का उपयोग किया गया था:

  • यदि उपयोग किया जाता है, तो पैटर्न लागू होने की संभावना है, और अधिक महत्वपूर्ण बात, सही ढंग से लागू (बस यह जांचें कि एक protectedकीवर्ड है),
  • यदि उपयोग नहीं किया गया है, तो आप जांच करने की कोशिश कर सकते हैं कि यह क्यों नहीं था।

मैक्रोज़ के बिना, आपको यह निरीक्षण करना होगा कि क्या पैटर्न सभी मामलों में आवश्यक और अच्छी तरह से लागू है।

बेहतर समाधान

  • क्या कोई दूसरा, बेहतर उपाय है?

C ++ में Slicing भाषा की ख़ासियत से अधिक कुछ नहीं है। चूँकि आपकी गाइडलाइन लिख रही हैं (newbies के लिए), आपको शिक्षण पर ध्यान केंद्रित करना चाहिए न कि "कोडिंग नियमों" की गणना करना चाहिए। आपको यह सुनिश्चित करना होगा कि आप वास्तव में समझाएं कि स्लाइसिंग कैसे और क्यों होती है, उदाहरणों और अभ्यासों के साथ (पहिया को सुदृढ़ न करें, पुस्तकों और ट्यूटोरियल से प्रेरणा प्राप्त करें)।

उदाहरण के लिए, एक अभ्यास का शीर्षक " C ++ में सुरक्षित इंटरफ़ेस के लिए पैटर्न क्या है ?"

तो, आपका सबसे अच्छा कदम यह सुनिश्चित करना होगा कि आपके सी ++ डेवलपर्स यह समझें कि स्लाइसिंग होने पर क्या हो रहा है। मुझे विश्वास है कि यदि वे ऐसा करते हैं, तो वे कोड में उतनी गलतियाँ नहीं करेंगे, जितनी आपको डर है, यहाँ तक कि औपचारिक रूप से उस विशेष पैटर्न को लागू किए बिना (लेकिन आप अभी भी इसे लागू कर सकते हैं, संकलक चेतावनी अच्छी हैं)।

संकलक के बारे में

तुम कहो :

मैं इस उत्पाद के लिए संकलक की पसंद पर कोई शक्ति नहीं है,

अक्सर लोग कहेंगे "मुझे [X] करने का अधिकार नहीं है" , "मैं ऐसा करने वाला नहीं हूं [Y] ..." , ... क्योंकि उन्हें लगता है कि यह संभव नहीं है, और इसलिए नहीं कि वे ऐसा नहीं करते हैं कोशिश की या पूछा।

तकनीकी मुद्दों के बारे में अपनी राय देने के लिए यह संभवतः आपके नौकरी विवरण का हिस्सा है; यदि आपको लगता है कि संकलक आपकी समस्या डोमेन के लिए सही (या अद्वितीय) विकल्प है, तो इसका उपयोग करें। लेकिन आपने यह भी कहा "इनलाइन कार्यान्वयन के साथ शुद्ध आभासी विध्वंसक सबसे खराब चोकिंग पॉइंट नहीं है जो मैंने देखा है" ; मेरी समझ से, कंपाइलर इतना खास है कि जानकार सी ++ डेवलपर्स को भी इसका इस्तेमाल करने में मुश्किलें आती हैं: आपकी विरासत / इन-हाउस कंपाइलर अब तकनीकी कर्ज है, और आपके पास उस अधिकार (कर्तव्य) पर है कि अन्य डिवेलपर्स और मैनेजरों के साथ उस मुद्दे पर चर्चा करें? ।

संकलक बनाम एक और एक का उपयोग करने की लागत रखने की लागत का आकलन करने का प्रयास करें:

  1. वर्तमान संकलक आपको क्या लाता है जो कोई अन्य नहीं कर सकता है?
  2. क्या आपका उत्पाद कोड आसानी से किसी अन्य संकलक का उपयोग करने योग्य है? क्यों नहीं ?

मुझे आपकी स्थिति का पता नहीं है, और वास्तव में आपके पास संभवतः एक विशिष्ट संकलक से बंधे होने के लिए वैध कारण हैं।
लेकिन अगर यह सिर्फ सादा जड़ता है, तो स्थिति कभी भी विकसित नहीं होगी यदि आप या आपके सहकर्मी उत्पादकता या तकनीकी ऋण समस्याओं की रिपोर्ट नहीं करते हैं।


Am I paranoid...: "सही ढंग से उपयोग करने के लिए अपने इंटरफेस को आसान बनाएं, और गलत तरीके से उपयोग करना मुश्किल है"। मैंने उस विशेष सिद्धांत को चखा है, जब किसी ने मेरे स्टैटिक तरीकों की रिपोर्ट की, गलती से, गलत तरीके से इस्तेमाल किया गया था। उत्पादित त्रुटि असंबंधित लग रही थी, और स्रोत को खोजने में कई घंटे लग गए। यह "इंटरफ़ेस त्रुटि" एक इंटरफ़ेस संदर्भ दूसरे को निर्दिष्ट करने के साथ है। तो, हां, मैं उस तरह की त्रुटि से बचना चाहता हूं। साथ ही, C ++ में, संकलन समय पर दर्शन को अधिक से अधिक पकड़ना है, और भाषा हमें वह शक्ति प्रदान करती है, इसलिए हम इसके साथ चलते हैं।
पियरसबल

Best solution: मैं सहमत हूँ। । । Better solution: यह एक भयानक जवाब है। मैं इस पर काम करूँगा ... अब, इस बारे में Pure virtual classes: यह क्या है? एक सी ++ सार इंटरफेस? (राज्य और केवल शुद्ध आभासी तरीकों के बिना वर्ग?)। इस "शुद्ध आभासी वर्ग" ने मुझे स्लाइसिंग से कैसे बचाया? (शुद्ध आभासी विधियाँ संकलन को संकलित नहीं करेंगी, लेकिन प्रतिलिपि-असाइनमेंट करेंगे, और असाइनमेंट को स्थानांतरित करेंगे, IIRC भी)।
पियरसबल

About the compiler: हम सहमत हैं, लेकिन हमारे संकलक मेरी जिम्मेदारी के दायरे से बाहर हैं (ऐसा नहीं है कि यह मुझे भद्दी टिप्पणियों से रोकता है ...: -प ...)। मैं विवरण का खुलासा नहीं करूंगा (काश मैं ऐसा कर सकता था) लेकिन यह आंतरिक कारणों (जैसे परीक्षण सूट) और बाहरी कारणों (जैसे हमारे पुस्तकालयों के साथ ग्राहक को जोड़ने) से बंधा है। अंत में, संकलक संस्करण को बदलना (या यहां तक ​​कि इसे पैच करना) एक तुच्छ ऑपरेशन नहीं है। अकेले एक हाल ही में जीसीसी के साथ एक टूटे हुए कंपाइलर को बदलने दें।
पियरसबल

@paercebal आपकी टिप्पणियों के लिए धन्यवाद; शुद्ध आभासी कक्षाओं के बारे में, आप सही हैं, यह आपके सभी बाधाओं को हल नहीं करता है (मैं इस हिस्से को हटा दूंगा)। मैं "इंटरफ़ेस त्रुटि" भाग को समझता हूं और संकलन-समय पर त्रुटियों को कैसे पकड़ना उपयोगी है: लेकिन आपने पूछा कि क्या आप पागल हैं, और मुझे लगता है कि तर्कसंगत दृष्टिकोण गलती की संभावना के साथ स्थिर जांच के लिए आपकी आवश्यकता को संतुलित करना है। संकलक के साथ शुभकामनाएँ :)
coredump

1
मैं मैक्रों का प्रशंसक नहीं हूं, खासकर क्योंकि दिशानिर्देश जूनियर (पुरुष) पर भी लक्षित होते हैं। बहुत बार, मैंने ऐसे लोगों को देखा है, जिन्हें इस तरह के "आसान" उपकरण दिए गए थे कि वे उन्हें नेत्रहीन रूप से लागू कर सकें और यह कभी नहीं समझ पाएंगे कि वास्तव में क्या चल रहा था। वे मानते हैं कि मैक्रो सबसे जटिल चीज क्या है क्योंकि उनके बॉस ने सोचा था कि उनके लिए खुद को करना बहुत मुश्किल होगा। और क्योंकि मैक्रो केवल आपकी कंपनी में मौजूद है, वे इसके लिए एक वेब खोज भी नहीं कर सकते हैं, जबकि एक दस्तावेज गाइडलाइन के लिए कि कौन सा सदस्य घोषित करने के लिए कार्य करता है और क्यों, वे कर सकते हैं।
5gon12eder

2

स्लाइसिंग की समस्या एक है, लेकिन निश्चित रूप से केवल एक ही नहीं है, जब आप अपने उपयोगकर्ताओं के लिए एक रन-टाइम बहुरूपी इंटरफ़ेस उजागर करते हैं। अशक्त संकेत, स्मृति प्रबंधन, साझा डेटा के बारे में सोचो। इनमें से कोई भी आसानी से सभी मामलों में हल नहीं किया जाता है (स्मार्ट पॉइंटर्स महान हैं, लेकिन यहां तक ​​कि वे कोई चांदी की गोली नहीं हैं)। वास्तव में, आपके पोस्ट से ऐसा नहीं लगता है कि आप स्लाइसिंग की समस्या को हल करने की कोशिश कर रहे हैं , बल्कि उपयोगकर्ताओं को प्रतियां बनाने की अनुमति नहीं देकर इसे दरकिनार कर रहे हैं। स्लाइसिंग समस्या के समाधान की पेशकश करने के लिए आपको बस एक वर्चुअल क्लोन सदस्य फ़ंक्शन जोड़ना होगा। मुझे लगता है कि एक रन-टाइम पॉलीमॉर्फिक इंटरफ़ेस को उजागर करने में गहरी समस्या यह है कि आप उपयोगकर्ताओं को संदर्भ शब्दार्थ से निपटने के लिए मजबूर करते हैं, जो मूल्य शब्दार्थ की तुलना में तर्क के लिए कठिन हैं।

C ++ में इन समस्याओं से बचने का जो सबसे अच्छा तरीका मुझे पता है वह है टाइप इरेज़र का उपयोग करना । यह एक तकनीक है जहां आप एक सामान्य वर्ग इंटरफ़ेस के पीछे एक रन-टाइम बहुरूपी इंटरफ़ेस छिपाते हैं। इस सामान्य वर्ग के इंटरफ़ेस में मूल्य शब्दार्थ है और स्क्रीन के पीछे सभी पॉलीमॉर्फिक 'मेस' की देखभाल करता है। std::functionप्रकार के क्षरण का एक प्रमुख उदाहरण है।

अपने उपयोगकर्ताओं के उत्तराधिकार को उजागर करने के तरीके के बारे में एक महान विवरण के लिए यह बुरा है और शमन माता-पिता द्वारा इन प्रस्तुतियों को देखने के लिए कैसे ठीक करने में मदद मिल सकती है:

वंशानुक्रम ईविल का आधार वर्ग (लघु संस्करण) है

मूल्य शब्दार्थ और अवधारणा-आधारित बहुरूपता (लंबा संस्करण; अनुसरण करने में आसान, लेकिन ध्वनि महान नहीं है)


0

तुम पागल नहीं हो। C ++ प्रोग्रामर के रूप में मेरा पहला पेशेवर कार्य स्लाइसिंग और क्रैश में हुआ। मुझे दूसरों का पता है। इसके लिए बहुत सारे अच्छे समाधान नहीं हैं।

अपने संकलक बाधाओं को देखते हुए, विकल्प 2 सबसे अच्छा है। एक मैक्रो बनाने के बजाय, जिसे आपके नए प्रोग्रामर अजीब और रहस्यमय देखेंगे, मैं कोड बनाने वाले ऑटो के लिए एक स्क्रिप्ट या टूल का सुझाव दूंगा। यदि आपके नए कर्मचारी एक IDE का उपयोग कर रहे हैं, तो आपको एक "नया MYCOMPANY इंटरफ़ेस" उपकरण बनाने में सक्षम होना चाहिए जो इंटरफ़ेस नाम के लिए पूछेगा, और उस संरचना का निर्माण करेगा जिसे आप ढूंढ रहे हैं।

यदि आपके प्रोग्रामर कमांड लाइन का उपयोग कर रहे हैं, तो कोड उत्पन्न करने के लिए NewMyCompanyInterface स्क्रिप्ट बनाने के लिए जो भी स्क्रिप्टिंग भाषा आपके पास उपलब्ध है, उसका उपयोग करें।

मैंने इस दृष्टिकोण का उपयोग आम कोड पैटर्न (इंटरफेस, स्टेट मशीन आदि) के लिए किया है। अच्छी बात यह है कि नए प्रोग्रामर आउटपुट को पढ़ सकते हैं और इसे आसानी से समझ सकते हैं, आवश्यक कोड को पुन: प्रस्तुत कर सकते हैं जब उन्हें कुछ ऐसा चाहिए जो उत्पन्न नहीं हो सकता है।

मैक्रोज़ और अन्य मेटा-प्रोग्रामिंग दृष्टिकोण क्या हो रहा है, इस बात को मानने के लिए करते हैं, और नए प्रोग्रामर यह नहीं सीखते हैं कि 'पर्दे के पीछे' क्या हो रहा है। जब उन्हें पैटर्न को तोड़ना होता है, तो वे पहले की तरह ही खो जाते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.