किसी ने इसका उल्लेख आईआरसी में स्लाइसिंग समस्या के रूप में किया।
किसी ने इसका उल्लेख आईआरसी में स्लाइसिंग समस्या के रूप में किया।
जवाबों:
"स्लाइसिंग" वह जगह है जहाँ आप एक व्युत्पन्न वर्ग की एक वस्तु को एक बेस क्लास के उदाहरण के लिए असाइन करते हैं, जिससे जानकारी का कुछ हिस्सा खो जाता है - इसमें से कुछ "कटा हुआ" है।
उदाहरण के लिए,
class A {
int foo;
};
class B : public A {
int bar;
};
तो एक प्रकार B
की वस्तु में दो डेटा सदस्य होते हैं, foo
औरbar
।
तो अगर आप यह लिखने के लिए थे:
B b;
A a = b;
फिर b
सदस्य के बारे में जानकारी bar
खो जाती है a
।
A a = b;
a
अब A
उस प्रकार की वस्तु है जिसकी कॉपी है B::foo
। यह अब मुझे लगता है कि इसे कास्ट करने के लिए गलती होगी।
B b1; B b2; A& b2_ref = b2; b2 = b1
। आप सोच सकते हैं कि आपने नकल की b1
है b2
, लेकिन आपने नहीं की है! तुम एक की नकल की है भाग के b1
लिए b2
(का हिस्सा b1
है कि B
से विरासत में मिली A
है), और के अन्य भागों के लिए छोड़ दिया b2
अपरिवर्तित। b2
अब एक फ्रेंकस्टीनियन प्राणी है, जिसमें b1
कुछ विखंडू होते हैं b2
। ओह! डाउनवोटिंग क्योंकि मुझे लगता है कि इसका उत्तर बहुत भ्रामक है।
B b1; B b2; A& b2_ref = b2; b2_ref = b1
" वास्तविक समस्या तब होती है जब आप " ... एक गैर-आभासी असाइनमेंट ऑपरेटर के साथ एक वर्ग से प्राप्त करते हैं। है A
भी व्युत्पत्ति लिए करना? इसका कोई आभासी कार्य नहीं है। यदि आप एक प्रकार से प्राप्त करते हैं, तो आपको इस तथ्य से निपटना होगा कि इसके सदस्य कार्यों को कहा जा सकता है!
यहां अधिकांश उत्तर यह स्पष्ट करने में विफल हैं कि स्लाइसिंग के साथ वास्तविक समस्या क्या है। वे केवल टुकड़ा करने के सौम्य मामलों की व्याख्या करते हैं, विश्वासघाती लोगों की नहीं। दूसरे उत्तरों की तरह मान लें, कि आप दो वर्गों के साथ काम कर रहे हैं A
और B
, जहाँ B
से (सार्वजनिक रूप से) प्राप्त होता है A
।
इस स्थिति में, सी ++ आप का एक उदाहरण से पारित की सुविधा देता है B
के लिए A
की असाइनमेंट ऑपरेटर (और यह भी प्रति निर्माता के लिए)। यह काम करता है क्योंकि एक उदाहरण B
को एक में परिवर्तित किया जा सकता है const A&
, जो कि असाइनमेंट ऑपरेटर और कॉपी-कंस्ट्रक्टर उनके तर्क होने की उम्मीद करते हैं।
B b;
A a = b;
वहां कुछ भी बुरा नहीं होता है - आपने एक उदाहरण के लिए कहा A
जिसकी एक प्रति है B
, और वास्तव में आपको यही मिलता है। ज़रूर, a
इसमें कुछ b
सदस्य नहीं होंगे, लेकिन यह कैसे होना चाहिए? यह एक है A
, सब के बाद, नहीं B
, तो यह इन सदस्यों के बारे में भी नहीं सुना है , अकेले उन्हें स्टोर करने में सक्षम हो जाएगा।
B b1;
B b2;
A& a_ref = b2;
a_ref = b1;
//b2 now contains a mixture of b1 and b2!
आप सोच सकते हैं कि बाद की b2
प्रति होगी b1
। लेकिन, अफसोस, यह नहीं है ! यदि आप इसका निरीक्षण करते हैं, तो आपको पता चलता है कि b2
एक फ्रेंकस्टीनियन प्राणी है, जो कुछ विखंडू से बना है b1
(जो विखंडन B
से विरासत में मिला है A
), और कुछ विखंडू b2
(केवल जो B
समाहित होता है)। आउच!
क्या हुआ? खैर, सी ++ डिफ़ॉल्ट रूप से असाइनमेंट ऑपरेटरों के रूप में व्यवहार नहीं करता है virtual
। इस प्रकार, रेखा a_ref = b1
असाइनमेंट ऑपरेटर को कॉल करेगी A
, इसके बारे में नहीं B
। ऐसा इसलिए है, क्योंकि गैर-आभासी कार्यों के लिए, घोषित (औपचारिक रूप से: स्थैतिक ) प्रकार (जो है A&
) निर्धारित करता है कि कौन सा फ़ंक्शन कहा जाता है, वास्तविक (औपचारिक रूप से: गतिशील ) प्रकार के विपरीत (जो होगा B
, क्योंकि a_ref
संदर्भ का एक उदाहरण है B
) । अब, A
असाइनमेंट ऑपरेटर स्पष्ट रूप से केवल घोषित किए गए सदस्यों के बारे में जानता है A
, इसलिए यह केवल उन लोगों को कॉपी करेगा, जो सदस्यों को जोड़ा गया हैB
अपरिवर्तित ।
केवल एक वस्तु के कुछ हिस्सों को सौंपना आमतौर पर बहुत कम समझ में आता है, फिर भी C ++, दुर्भाग्य से, इसे मना करने का कोई अंतर्निहित तरीका प्रदान नहीं करता है। हालाँकि, आप अपना स्वयं का रोल कर सकते हैं। पहला चरण असाइनमेंट ऑपरेटर को आभासी बना रहा है । यह गारंटी देगा कि यह हमेशा वास्तविक प्रकार का असाइनमेंट ऑपरेटर है जिसे कहा जाता है, घोषित प्रकार का नहीं। दूसरा चरण यह dynamic_cast
सत्यापित करने के लिए उपयोग करना है कि निर्दिष्ट ऑब्जेक्ट में एक संगत प्रकार है। तीसरे चरण एक (सुरक्षित!) सदस्य में वास्तविक काम करना है assign()
, के बाद से B
की assign()
शायद का उपयोग करना चाहते जाएगा A
'एस assign()
कॉपी करने के लिए A
की, सदस्य हैं।
class A {
public:
virtual A& operator= (const A& a) {
assign(a);
return *this;
}
protected:
void assign(const A& a) {
// copy members of A from a to this
}
};
class B : public A {
public:
virtual B& operator= (const A& a) {
if (const B* b = dynamic_cast<const B*>(&a))
assign(*b);
else
throw bad_assignment();
return *this;
}
protected:
void assign(const B& b) {
A::assign(b); // Let A's assign() copy members of A from b to this
// copy members of B from b to this
}
};
ध्यान दें कि, शुद्ध सुविधा के लिए, B
's operator=
covariantly, वापसी प्रकार ओवरराइड करता है के बाद से यह जानता है कि यह का एक उदाहरण लौटा रहा है B
।
derived
मूल्य को उम्मीद करने वाले कोड को दिया जा सकता है base
, या किसी व्युत्पन्न संदर्भ को आधार संदर्भ के रूप में उपयोग किया जा सकता है। मैं एक भाषा को एक प्रकार की प्रणाली के साथ देखना चाहता हूं जो दोनों अवधारणाओं को अलग-अलग संबोधित करता है। ऐसे कई मामले हैं जहां एक व्युत्पन्न संदर्भ को आधार संदर्भ के लिए प्रतिस्थापित किया जाना चाहिए, लेकिन व्युत्पन्न उदाहरणों को आधार के लिए प्रतिस्थापित नहीं किया जाना चाहिए; ऐसे कई मामले भी हैं जहां उदाहरण परिवर्तनीय होने चाहिए लेकिन संदर्भ स्थानापन्न नहीं होने चाहिए।
यदि आपके पास एक आधार वर्ग A
और एक व्युत्पन्न वर्ग है B
, तो आप निम्न कार्य कर सकते हैं।
void wantAnA(A myA)
{
// work with myA
}
B derived;
// work with the object "derived"
wantAnA(derived);
अब विधि wantAnA
की एक प्रति की आवश्यकता है derived
। हालाँकि, ऑब्जेक्ट derived
को पूरी तरह से कॉपी नहीं किया जा सकता है, क्योंकि वर्ग B
अतिरिक्त सदस्य चर का आविष्कार कर सकता है जो इसके आधार वर्ग में नहीं हैं A
।
इसलिए, कॉल करने के लिए wantAnA
, कंपाइलर व्युत्पन्न वर्ग के सभी अतिरिक्त सदस्यों को "स्लाइस ऑफ" करेगा। परिणाम एक ऐसी वस्तु हो सकती है जिसे आप बनाना नहीं चाहते थे, क्योंकि
A
-object की तरह व्यवहार करता है (वर्ग B
का सभी विशेष व्यवहार खो जाता है)।wantAnA
(जैसा कि इसके नाम का अर्थ है!) एक चाहता है A
, तो यह वही है जो इसे प्राप्त करता है। और A
, इच्छा, उह, का एक उदाहरण एक की तरह व्यवहार करता है A
। यह आश्चर्य की बात कैसे है?
derived
टाइप से करता है A
। इंप्लिक्ट कास्टिंग हमेशा C ++ में अप्रत्याशित व्यवहार का एक स्रोत है, क्योंकि अक्सर स्थानीय रूप से कोड को देखने से समझना मुश्किल है कि एक कास्ट जगह है।
ये सभी अच्छे उत्तर हैं। मैं संदर्भ द्वारा मूल्य के संदर्भ में वस्तुओं को पारित करते समय एक निष्पादन उदाहरण जोड़ना चाहूंगा:
#include <iostream>
using namespace std;
// Base class
class A {
public:
A() {}
A(const A& a) {
cout << "'A' copy constructor" << endl;
}
virtual void run() const { cout << "I am an 'A'" << endl; }
};
// Derived class
class B: public A {
public:
B():A() {}
B(const B& a):A(a) {
cout << "'B' copy constructor" << endl;
}
virtual void run() const { cout << "I am a 'B'" << endl; }
};
void g(const A & a) {
a.run();
}
void h(const A a) {
a.run();
}
int main() {
cout << "Call by reference" << endl;
g(B());
cout << endl << "Call by copy" << endl;
h(B());
}
आउटपुट है:
Call by reference
I am a 'B'
Call by copy
'A' copy constructor
I am an 'A'
"C ++ स्लाइसिंग" के लिए Google में तीसरा मैच मुझे यह विकिपीडिया लेख http://en.wikipedia.org/wiki/Object_slicing और यह (गर्म, लेकिन पहले कुछ पोस्ट समस्या को परिभाषित करता है) देता है: http://bytes.com/ मंच / thread163565.html
तो यह तब होता है जब आप सुपर क्लास को एक उपवर्ग का ऑब्जेक्ट सौंपते हैं। सुपरक्लास को उपवर्ग में अतिरिक्त जानकारी के बारे में कुछ नहीं पता है, और इसे स्टोर करने के लिए जगह नहीं मिली है, इसलिए अतिरिक्त जानकारी "कटा हुआ" हो जाता है।
यदि वे लिंक "अच्छे उत्तर" के लिए पर्याप्त जानकारी नहीं देते हैं, तो कृपया अपने प्रश्न को संपादित करें ताकि हमें पता चल सके कि आप और क्या देख रहे हैं।
स्लाइसिंग की समस्या गंभीर है क्योंकि इसके परिणामस्वरूप मेमोरी में भ्रष्टाचार हो सकता है, और यह गारंटी देना बहुत मुश्किल है कि किसी प्रोग्राम को इससे नुकसान न हो। इसे भाषा से डिजाइन करने के लिए, विरासत का समर्थन करने वाली कक्षाएं केवल संदर्भ द्वारा (मूल्य से नहीं) सुलभ होनी चाहिए। डी प्रोग्रामिंग भाषा में यह संपत्ति है।
क्लास ए पर विचार करें, और ए। मेमोरी भ्रष्टाचार से उत्पन्न वर्ग बी हो सकता है यदि ए के हिस्से में पॉइंटर पी, और बी उदाहरण है जो बी के अतिरिक्त डेटा को इंगित करता है। फिर, जब अतिरिक्त डेटा बंद हो जाता है, तो पी कचरा की ओर इशारा करता है।
Derived
यह अनुमानित रूप से परिवर्तनीय है Base
।) यह स्पष्ट रूप से ओपन-क्लोज्ड प्रिंसिपल और एक बड़ा रखरखाव बोझ के लिए काउंटर है।
C ++ में, एक व्युत्पन्न वर्ग वस्तु को एक बेस क्लास ऑब्जेक्ट को सौंपा जा सकता है, लेकिन दूसरा तरीका संभव नहीं है।
class Base { int x, y; };
class Derived : public Base { int z, w; };
int main()
{
Derived d;
Base b = d; // Object Slicing, z and w of d are sliced off
}
ऑब्जेक्ट स्लाइसिंग तब होता है जब एक व्युत्पन्न वर्ग ऑब्जेक्ट को बेस क्लास ऑब्जेक्ट को सौंपा जाता है, बेस क्लास ऑब्जेक्ट बनाने के लिए एक व्युत्पन्न क्लास ऑब्जेक्ट की अतिरिक्त विशेषताओं को कटा हुआ होता है।
C ++ में स्लाइसिंग समस्या इसकी वस्तुओं के मूल्य शब्दार्थ से उत्पन्न होती है, जो ज्यादातर C संरचनाओं के साथ संगतता के कारण बनी हुई है। आपको अधिकांश अन्य भाषाओं में पाए जाने वाले "सामान्य" ऑब्जेक्ट व्यवहार को प्राप्त करने के लिए स्पष्ट संदर्भ या पॉइंटर सिंटैक्स का उपयोग करने की आवश्यकता है, जो ऑब्जेक्ट्स करते हैं, अर्थात, ऑब्जेक्ट्स को हमेशा संदर्भ द्वारा पास किया जाता है।
संक्षिप्त उत्तर यह है कि आप किसी वस्तु को मान द्वारा आधार वस्तु पर नियत करके वस्तु का टुकड़ा करते हैं , अर्थात शेष वस्तु व्युत्पन्न वस्तु का ही एक हिस्सा है। मूल्य शब्दार्थों को संरक्षित करने के लिए, स्लाइसिंग एक उचित व्यवहार है और इसके अपेक्षाकृत दुर्लभ उपयोग हैं, जो अधिकांश अन्य भाषाओं में मौजूद नहीं है। कुछ लोग इसे C ++ की विशेषता मानते हैं, जबकि कई इसे C ++ के क्विर्क / मिसफिटर्स में से एक मानते हैं।
struct
नहीं है जो किसी भी यादृच्छिक ओओपी पुजारी ने आपको बताया था।
Base
बिल्कुल sizeof(Base)
बाइट्स लेना चाहिए , शायद, इसलिए "असाइनमेंट" (ऑन-स्टैक-कॉपी ) व्युत्पन्न वर्ग के सदस्यों की नकल नहीं करेंगे, उनके ऑफ़सेट आकार के बाहर हैं। "डेटा खोने" से बचने के लिए, बस सूचक का उपयोग करें, किसी और की तरह, क्योंकि सूचक मेमोरी जगह और आकार में तय की गई है, जबकि स्टैक बहुत ही अस्थिर है
तो ... क्यों व्युत्पन्न जानकारी खराब हो रही है? ... क्योंकि व्युत्पन्न वर्ग के लेखक ने प्रतिनिधित्व को बदल दिया हो सकता है जैसे कि अतिरिक्त जानकारी को हटाने से वस्तु द्वारा दर्शाए जा रहे मूल्य में परिवर्तन होता है। यह तब हो सकता है यदि व्युत्पन्न वर्ग अगर एक प्रतिनिधित्व को कैश करने के लिए उपयोग किया जाता है जो कुछ कार्यों के लिए अधिक कुशल है, लेकिन आधार प्रतिनिधित्व में वापस बदलने के लिए महंगा है।
यह भी सोचा कि किसी को भी उल्लेख करना चाहिए कि आपको स्लाइसिंग से बचने के लिए क्या करना चाहिए ... C ++ कोडिंग मानकों की एक प्रति प्राप्त करें, 101 नियम दिशानिर्देश और सर्वोत्तम अभ्यास। टुकड़ा करने की क्रिया # 54 है।
यह समस्या से पूरी तरह से निपटने के लिए कुछ हद तक परिष्कृत पैटर्न का सुझाव देता है: एक संरक्षित प्रतिलिपि निर्माता, एक संरक्षित शुद्ध आभासी DoClone और एक सार्वजनिक क्लोन है जो आपको बताएगा कि क्या एक (आगे) व्युत्पन्न वर्ग DoClone को सही तरीके से लागू करने में विफल रहा है। (क्लोन विधि बहुरूपी वस्तु की उचित गहरी प्रतिलिपि बनाती है।)
आप आधार पर कॉपी कंस्ट्रक्टर को भी स्पष्ट रूप से चिह्नित कर सकते हैं जो वांछित होने पर स्पष्ट टुकड़ा करने की अनुमति देता है।
1. SLICING PROBLEM की परिभाषा
यदि D बेस क्लास B का एक व्युत्पन्न वर्ग है, तो आप टाइप बेस के एक चर (या पैरामीटर) के लिए व्युत्पन्न प्रकार की वस्तु को असाइन कर सकते हैं।
उदाहरण
class Pet
{
public:
string name;
};
class Dog : public Pet
{
public:
string breed;
};
int main()
{
Dog dog;
Pet pet;
dog.name = "Tommy";
dog.breed = "Kangal Dog";
pet = dog;
cout << pet.breed; //ERROR
यद्यपि उपरोक्त असाइनमेंट की अनुमति है, लेकिन चर पालतू को सौंपा गया मूल्य इसकी नस्ल क्षेत्र खो देता है। इसे स्लाइसिंग समस्या कहा जाता है ।
2. SLIC PROBLEM को कैसे फिट करें
समस्या को हराने के लिए, हम पॉइंटर्स को डायनामिक वैरिएबल का उपयोग करते हैं।
उदाहरण
Pet *ptrP;
Dog *ptrD;
ptrD = new Dog;
ptrD->name = "Tommy";
ptrD->breed = "Kangal Dog";
ptrP = ptrD;
cout << ((Dog *)ptrP)->breed;
इस स्थिति में, ptrD (अवर श्रेणी के ऑब्जेक्ट) द्वारा इंगित किए जा रहे डायनामिक वैरिएबल का कोई भी डेटा सदस्य या सदस्य कार्य नहीं खोएगा। इसके अलावा, यदि आपको फ़ंक्शन का उपयोग करने की आवश्यकता है, तो फ़ंक्शन एक वर्चुअल फ़ंक्शन होना चाहिए।
dog
वर्ग का हिस्सा नहीं है Pet
( breed
डेटा सदस्य) चर में कॉपी नहीं किया गया है pet
? कोड केवल Pet
डेटा सदस्यों में रुचि रखता है - जाहिरा तौर पर। अगर यह अवांछित है, तो स्लाइसिंग निश्चित रूप से एक "समस्या" है, लेकिन मैं इसे यहाँ नहीं देखता।
((Dog *)ptrP)
" मैं सुझाव देता हूंstatic_cast<Dog*>(ptrP)
Dog::breed
कोई तरीका नहीं है) SLICING से संबंधित ERROR है?
यह मुझे लगता है, कि जब आपके स्वयं के कक्षाएं और कार्यक्रम खराब रूप से आर्किटेक्चर / डिज़ाइन किए गए हैं, तो इसके अलावा स्लाइसिंग इतनी समस्या नहीं है।
यदि मैं एक उप-प्रकार की वस्तु को एक विधि के पैरामीटर के रूप में पास करता हूं, जो कि प्रकार के सुपरक्लास का एक पैरामीटर लेता है, तो मुझे निश्चित रूप से इसके बारे में पता होना चाहिए और आंतरिक रूप से पता होना चाहिए, कहा जाता है कि विधि सुपरक्लास (उर्फ बास्केट) ऑब्जेक्ट के साथ ही काम करेगी।
यह मुझे केवल अनुचित उम्मीद है कि एक उपवर्ग प्रदान करने का अनुरोध करता है जहां एक बेसकलैस का अनुरोध किया जाता है, जो किसी भी तरह से उपवर्ग विशिष्ट परिणाम देगा, जिससे समस्या का कारण बन जाएगा। विधि के उपयोग में इसका या तो खराब डिज़ाइन या घटिया उपवर्ग कार्यान्वयन। मैं अनुमान लगा रहा हूँ कि इसका परिणाम आमतौर पर अच्छा ओओपी डिज़ाइन का विस्तार या प्रदर्शन के लाभ के पक्ष में त्याग है।
ठीक है, मैं ऑब्जेक्ट स्लाइसिंग समझाते हुए कई पोस्ट पढ़ने के बाद यह कोशिश करूँगा लेकिन यह नहीं कि यह समस्याग्रस्त कैसे हो जाता है।
स्मृति भ्रष्टाचार के परिणामस्वरूप होने वाला दुष्परिणाम निम्नलिखित है:
स्लाइसिंग का अर्थ है कि उप-वर्ग द्वारा जोड़ा गया डेटा तब छोड़ दिया जाता है जब उप-वर्ग का ऑब्जेक्ट पास हो जाता है या मान द्वारा या किसी बेस क्लास ऑब्जेक्ट की अपेक्षा वाले फ़ंक्शन से वापस आ जाता है।
स्पष्टीकरण: निम्नलिखित वर्ग घोषणा पर विचार करें:
class baseclass
{
...
baseclass & operator =(const baseclass&);
baseclass(const baseclass&);
}
void function( )
{
baseclass obj1=m;
obj1=m;
}
जैसा कि बेसकलैस कॉपी फ़ंक्शंस के बारे में कुछ भी नहीं पता है कि व्युत्पन्न के आधार भाग की प्रतिलिपि बनाई गई है। इसे आमतौर पर स्लाइसिंग कहा जाता है।
class A
{
int x;
};
class B
{
B( ) : x(1), c('a') { }
int x;
char c;
};
int main( )
{
A a;
B b;
a = b; // b.c == 'a' is "sliced" off
return 0;
}
जब एक व्युत्पन्न वर्ग वस्तु को एक बेस क्लास ऑब्जेक्ट को सौंपा जाता है, तो एक व्युत्पन्न वर्ग ऑब्जेक्ट की अतिरिक्त विशेषताओं को आधार वर्ग ऑब्जेक्ट के रूप में बंद कर दिया जाता है।
class Base {
int x;
};
class Derived : public Base {
int z;
};
int main()
{
Derived d;
Base b = d; // Object Slicing, z of d is sliced off
}
जब एक व्युत्पन्न वर्ग ऑब्जेक्ट बेस क्लास ऑब्जेक्ट को सौंपा जाता है, तो व्युत्पन्न वर्ग ऑब्जेक्ट के सभी सदस्यों को बेस क्लास ऑब्जेक्ट के लिए कॉपी किया जाता है, केवल उन सदस्यों को छोड़कर जो बेस क्लास में मौजूद नहीं हैं। इन सदस्यों को संकलक द्वारा अलग कर दिया जाता है। इसे ऑब्जेक्ट स्लिंग कहते हैं।
यहाँ एक उदाहरण है:
#include<bits/stdc++.h>
using namespace std;
class Base
{
public:
int a;
int b;
int c;
Base()
{
a=10;
b=20;
c=30;
}
};
class Derived : public Base
{
public:
int d;
int e;
Derived()
{
d=40;
e=50;
}
};
int main()
{
Derived d;
cout<<d.a<<"\n";
cout<<d.b<<"\n";
cout<<d.c<<"\n";
cout<<d.d<<"\n";
cout<<d.e<<"\n";
Base b = d;
cout<<b.a<<"\n";
cout<<b.b<<"\n";
cout<<b.c<<"\n";
cout<<b.d<<"\n";
cout<<b.e<<"\n";
return 0;
}
यह उत्पन्न करेगा:
[Error] 'class Base' has no member named 'd'
[Error] 'class Base' has no member named 'e'
मैं बस स्लाइसिंग समस्या के दौरान भाग गया और तुरंत यहां उतरा। तो मुझे इसमें अपने दो सेंट जोड़ने चाहिए।
चलो "प्रोडक्शन कोड" (या ऐसा कुछ जो करीबी आता है) से एक उदाहरण है:
मान लीजिए कि हमारे पास कुछ है जो कार्यों को भेजता है। उदाहरण के लिए एक नियंत्रण केंद्र UI।
इस UI को उन चीजों की एक सूची प्राप्त करने की आवश्यकता है जो वर्तमान में भेजे जाने में सक्षम हैं। इसलिए हम एक वर्ग को परिभाषित करते हैं जिसमें प्रेषण-जानकारी होती है। चलो इसे बुलाओ Action
। तो Action
कुछ सदस्य चर है। सादगी के लिए हमारे पास सिर्फ 2 हैं, एक std::string name
और एक होने के नाते std::function<void()> f
। तब यह एक है void activate()
जो सिर्फ निष्पादित करता हैf
सदस्य होता है सदस्य को ।
तो यूआई को एक std::vector<Action>
आपूर्ति मिलती है । कुछ कार्यों की कल्पना करें जैसे:
void push_back(Action toAdd);
अब हमने स्थापित किया है कि यह UI के दृष्टिकोण से कैसा दिखता है। अब तक कोई समस्या नहीं। लेकिन इस परियोजना पर काम करने वाले कुछ अन्य व्यक्ति अचानक निर्णय लेते हैं कि ऐसे विशेष कार्य हैं जो Action
वस्तु में अधिक जानकारी की आवश्यकता है । किस कारण से यह भी लंबोदर कब्जा के साथ हल किया जा सकता है। यह उदाहरण कोड से 1-1 नहीं लिया गया है।
तो आदमी Action
अपने स्वाद को जोड़ने के लिए प्राप्त करता है ।
वह अपने घर से पीसा हुआ वर्ग के एक उदाहरण के लिए गुजरता है, push_back
लेकिन फिर कार्यक्रम haywire जाता है।
तो क्या हुआ?
जैसा कि आप अनुमान लगा सकते हैं: ऑब्जेक्ट कटा हुआ है।
उदाहरण से अतिरिक्त जानकारी खो गई है, और f
अब अपरिभाषित व्यवहार का खतरा है।
मुझे उम्मीद है कि यह उदाहरण उन लोगों के लिए प्रकाश लाता है जो वास्तव में चीजों की कल्पना नहीं कर सकते हैं जब A
एस और B
एस के बारे में किसी तरह से बात की जा रही है।