มีคนพูดถึงมันใน IRC ว่าเป็นปัญหาการแบ่งส่วน
มีคนพูดถึงมันใน IRC ว่าเป็นปัญหาการแบ่งส่วน
คำตอบ:
"ตัวแบ่งส่วนข้อมูล" คือที่ที่คุณกำหนดวัตถุของคลาสที่ได้รับให้กับอินสแตนซ์ของคลาสพื้นฐานดังนั้นจึงสูญเสียส่วนหนึ่งของข้อมูล
ตัวอย่างเช่น,
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
ตอนนี้ก็เป็นสิ่งมีชีวิตที่ Frankensteinian ประกอบด้วยกี่บิตของตามด้วยชิ้นบางb1
b2
ฮึ Downvoting เพราะฉันคิดว่าคำตอบนั้นเป็นขีปนาวุธมาก
B b1; B b2; A& b2_ref = b2; b2_ref = b1
" ปัญหาจริงเกิดขึ้นถ้าคุณ " ... ได้รับมาจากคลาสที่มีตัวดำเนินการที่ไม่ใช่เสมือน คือA
ตั้งใจแม้สำหรับมา? มันไม่มีฟังก์ชั่นเสมือนจริง หากคุณได้รับจากประเภทคุณต้องจัดการกับความจริงที่ว่าฟังก์ชั่นสมาชิกสามารถเรียกได้!
คำตอบส่วนใหญ่ที่นี่ไม่สามารถอธิบายได้ว่าปัญหาจริงของการแบ่งส่วนข้อมูลคืออะไร พวกเขาอธิบายเฉพาะกรณีที่ไม่เป็นพิษเป็นภัยของการหั่นเท่านั้นไม่ใช่ผู้ทรยศ สมมติเช่นคำตอบอื่น ๆ ที่คุณจัดการกับสองชั้นA
และB
ที่B
บุคลากร (สาธารณะ) A
จาก
ในสถานการณ์เช่นนี้, C ++ ช่วยให้คุณผ่านตัวอย่างของB
การ A
ดำเนินการกำหนด 's (และยัง constructor สำเนา) สิ่งนี้ได้ผลเพราะอินสแตนซ์ของB
สามารถถูกแปลงเป็น a 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
มีเท่านั้น) อุ๊ย!
เกิดอะไรขึ้น? ดี, C ++ virtual
โดยค่าเริ่มต้นไม่ผู้ประกอบการที่ได้รับมอบหมายไม่ได้รักษาเป็น ดังนั้นสายa_ref = b1
จะเรียกผู้ประกอบการที่ได้รับมอบหมายของไม่ว่าA
B
เพราะนี่คือการทำงานที่ไม่เสมือนประกาศ (อย่างเป็นทางการ: คงที่ ) ประเภท (ซึ่งเป็นA&
) กำหนดซึ่งฟังก์ชั่นที่เรียกว่าเมื่อเทียบกับที่เกิดขึ้นจริง (อย่างเป็นทางการ: แบบไดนามิก ) ประเภท (ซึ่งจะมีB
ตั้งแต่a_ref
การอ้างอิงตัวอย่างของB
) . ตอนนี้A
ผู้ดำเนินการที่ได้รับมอบหมายอย่างชัดเจนรู้เพียงเกี่ยวกับสมาชิกที่ประกาศในA
ดังนั้นมันจะคัดลอกเฉพาะผู้ที่ออกจากสมาชิกเพิ่มในB
ไม่เปลี่ยนแปลง
การกำหนดให้บางส่วนของวัตถุโดยปกติแล้วจะมีเหตุผลเล็กน้อย แต่ C ++ โชคไม่ดีที่ไม่สามารถห้ามสิ่งนี้ได้ อย่างไรก็ตามคุณสามารถม้วนของคุณเอง ขั้นตอนแรกคือการทำให้ผู้ประกอบการที่ได้รับมอบหมายเสมือน สิ่งนี้จะรับประกันได้ว่ามันเป็นผู้ดำเนินการที่ได้รับมอบหมายประเภทจริงเสมอซึ่งเรียกว่าไม่ใช่ประเภทที่ประกาศ ขั้นตอนที่สองคือการใช้dynamic_cast
เพื่อตรวจสอบว่าวัตถุที่กำหนดมีชนิดที่เข้ากันได้ ขั้นตอนที่สามคือการทำการกำหนดที่เกิดขึ้นจริงใน (ล็อก) สมาชิกassign()
ตั้งแต่B
's assign()
อาจจะต้องการใช้A
' s 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 ++ เสมอเนื่องจากมักจะยากที่จะเข้าใจจากการดูรหัสในเครื่องที่นักแสดงเกิดขึ้น
นี่คือคำตอบที่ดีทั้งหมด ฉันแค่ต้องการเพิ่มตัวอย่างการดำเนินการเมื่อผ่านวัตถุโดยค่า vs โดยอ้างอิง:
#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'
การจับคู่ที่สามใน google สำหรับ "การแบ่ง C ++" ให้บทความวิกิพีเดียนี้แก่ฉันhttp://en.wikipedia.org/wiki/Object_slicingและสิ่งนี้ (ได้รับความร้อน แต่โพสต์สองสามข้อแรกระบุปัญหา): http://bytes.com/ ฟอรั่ม / thread163565.html
ดังนั้นเมื่อคุณกำหนดวัตถุของคลาสย่อยให้กับซุปเปอร์คลาส ซูเปอร์คลาสไม่ทราบข้อมูลเพิ่มเติมใด ๆ ในคลาสย่อยและยังไม่มีที่ว่างสำหรับจัดเก็บดังนั้นข้อมูลเพิ่มเติมจึงถูก "ตัดออก"
หากลิงก์เหล่านั้นไม่มีข้อมูลเพียงพอสำหรับ "คำตอบที่ดี" โปรดแก้ไขคำถามของคุณเพื่อแจ้งให้เราทราบว่าคุณต้องการอะไรอีก
ปัญหาการแบ่งส่วนมีความร้ายแรงเนื่องจากอาจทำให้หน่วยความจำเสียหายและเป็นเรื่องยากมากที่จะรับประกันว่าโปรแกรมจะไม่ประสบปัญหา ในการออกแบบนอกภาษาคลาสที่รองรับการสืบทอดควรเข้าถึงได้โดยอ้างอิงเท่านั้น (ไม่ใช่ตามค่า) ภาษาการเขียนโปรแกรม D มีคุณสมบัตินี้
พิจารณาคลาส A และคลาส B ที่ได้มาจากความเสียหายของหน่วยความจำ A อาจเกิดขึ้นได้หากส่วน A มีตัวชี้ p และอินสแตนซ์ B ที่ชี้ไปยังข้อมูลเพิ่มเติมของ B จากนั้นเมื่อข้อมูลเพิ่มเติมถูกตัดออก p จะชี้ไปที่ขยะ
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 struct คุณจำเป็นต้องใช้การอ้างอิงที่ชัดเจนหรือไวยากรณ์ของตัวชี้เพื่อให้บรรลุพฤติกรรมของวัตถุ "ปกติ" ที่พบในภาษาอื่น ๆ ส่วนใหญ่ที่ทำวัตถุคือวัตถุจะถูกส่งผ่านโดยการอ้างอิงเสมอ
คำตอบสั้น ๆ คือให้คุณทำการแบ่งวัตถุด้วยการกำหนดวัตถุที่ได้รับมาให้กับวัตถุฐานโดยค่าเช่นวัตถุที่เหลืออยู่เป็นเพียงส่วนหนึ่งของวัตถุที่ได้รับ เพื่อรักษาความหมายของค่าการแบ่งเป็นพฤติกรรมที่สมเหตุสมผลและมีการใช้งานที่ค่อนข้างหายากซึ่งไม่มีอยู่ในภาษาอื่น ๆ ส่วนใหญ่ บางคนคิดว่ามันเป็นคุณสมบัติของ C ++ ในขณะที่หลายคนคิดว่ามันเป็นหนึ่งใน quirks / misfeatures ของ C ++
struct
เข้ากันได้หรือความรู้สึกอื่น ๆ ที่ไม่ใช่นักบวช OOP สุ่มบอกคุณ
Base
จะต้องใช้sizeof(Base)
ไบต์ในหน่วยความจำตรงกับการจัดตำแหน่งที่เป็นไปได้บางทีนั่นอาจเป็นเหตุผลว่า ) จะไม่คัดลอกสมาชิกของคลาสที่ได้มา แต่ออฟเซ็ตของพวกเขามีขนาดภายนอก เพื่อหลีกเลี่ยง "การสูญเสียข้อมูล" ชี้การใช้งานเพียงแค่เหมือนคนอื่นเนื่องจากหน่วยความจำตัวชี้ได้รับการแก้ไขในสถานที่และขนาดในขณะที่สแต็คเป็นอย่างมาก volitile
ดังนั้น ... ทำไมการสูญเสียข้อมูลที่ได้รับจึงไม่ดี? ... เพราะผู้เขียนของคลาสที่ได้รับอาจมีการเปลี่ยนแปลงการเป็นตัวแทนดังกล่าวที่ตัดข้อมูลเพิ่มเติมการเปลี่ยนแปลงมูลค่าการเป็นตัวแทนของวัตถุ สิ่งนี้สามารถเกิดขึ้นได้หากคลาสที่ได้รับมาหากใช้เพื่อแคชการแสดงที่มีประสิทธิภาพมากขึ้นสำหรับการดำเนินการบางอย่าง แต่มีราคาแพงในการแปลงกลับเป็นการแสดงพื้นฐาน
ยังคิดว่าบางคนควรพูดถึงสิ่งที่คุณควรทำเพื่อหลีกเลี่ยงการแบ่ง ... รับสำเนาของมาตรฐานการเข้ารหัส C ++, แนวทางกฎ 101 ข้อและแนวทางปฏิบัติที่ดีที่สุด การจัดการกับการแบ่งเป็น # 54
มันแนะนำรูปแบบที่ค่อนข้างซับซ้อนในการจัดการกับปัญหาอย่างสมบูรณ์: มีตัวสร้างสำเนาที่ได้รับการป้องกัน DoClone เสมือนที่ได้รับการป้องกันที่บริสุทธิ์และ Clone สาธารณะที่มีการยืนยันซึ่งจะบอกคุณว่าคลาสที่ได้รับ (เพิ่มเติม) ล้มเหลว (วิธีการโคลนทำการคัดลอกวัตถุ polymorphic ที่เหมาะสม)
นอกจากนี้คุณยังสามารถทำเครื่องหมายตัวสร้างการคัดลอกบนฐานที่ชัดเจนซึ่งอนุญาตให้มีการแบ่งอย่างชัดเจนหากต้องการ
1. คำจำกัดความของปัญหาช่องว่าง
ถ้า 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. วิธีแก้ไขปัญหาการเสียดสี
ในการเอาชนะปัญหาเราใช้พอยน์เตอร์เป็นตัวแปรแบบไดนามิก
ตัวอย่าง
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
ดูเหมือนว่าสำหรับฉันแล้วการแบ่งส่วนไม่ได้เป็นปัญหาอย่างอื่นนอกจากเมื่อชั้นเรียนและโปรแกรมของคุณมีการออกแบบ / ออกแบบที่ไม่ดี
หากฉันส่งวัตถุ subclass เป็นพารามิเตอร์ไปยังวิธีการซึ่งใช้พารามิเตอร์ประเภท superclass ฉันควรทราบอย่างแน่นอนและรู้ว่าภายในวิธีที่เรียกใช้จะทำงานกับวัตถุ superclass (aka baseclass) เท่านั้น
สำหรับฉันแล้วดูเหมือนว่าจะมีความคาดหวังที่ไม่สมเหตุสมผลซึ่งการให้คลาสย่อยที่ร้องขอ baseclass นั้นจะส่งผลให้ผลลัพธ์เฉพาะคลาสย่อยนั้นอาจทำให้การแบ่งเป็นปัญหาได้ ทั้งการออกแบบที่ไม่ดีในการใช้วิธีการหรือการใช้งานคลาสย่อยที่ไม่ดี ฉันเดาว่ามันมักจะเป็นผลมาจากการเสียสละการออกแบบ OOP ที่ดีเพื่อประโยชน์ที่เพิ่มขึ้นหรือประสิทธิภาพที่เพิ่มขึ้น
ตกลงฉันจะลองทำหลังจากอ่านโพสต์มากมายที่อธิบายการแบ่งส่วนของวัตถุ แต่ไม่ใช่ว่าจะเป็นปัญหาได้อย่างไร
สถานการณ์เลวร้ายที่อาจส่งผลให้เกิดความเสียหายของหน่วยความจำคือ:
การแบ่งส่วนข้อมูลหมายถึงข้อมูลที่ถูกเพิ่มโดยคลาสย่อยถูกทิ้งเมื่อวัตถุของคลาสย่อยถูกส่งหรือส่งคืนโดยค่าหรือจากฟังก์ชันที่ต้องการวัตถุคลาสพื้นฐาน
คำอธิบาย: พิจารณาการประกาศคลาสต่อไปนี้:
class baseclass
{
...
baseclass & operator =(const baseclass&);
baseclass(const baseclass&);
}
void function( )
{
baseclass obj1=m;
obj1=m;
}
ในฐานะที่เป็นฟังก์ชั่นการคัดลอก baseclass ไม่ทราบอะไรเกี่ยวกับการได้รับเพียงส่วนฐานของการได้รับการคัดลอก โดยทั่วไปเรียกว่าการแบ่งส่วน
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
ขอเรียกว่า ดังนั้น a จึงAction
มีตัวแปรสมาชิกบางตัว เพื่อความง่ายเราก็มี 2 เป็นและstd::string name
std::function<void()> f
จากนั้นก็มีสิ่งvoid activate()
ที่เพิ่งดำเนินการf
สมาชิก
ดังนั้น UI จึงได้รับstd::vector<Action>
มา ลองนึกภาพฟังก์ชั่นบางอย่างเช่น:
void push_back(Action toAdd);
ตอนนี้เราได้สร้างรูปลักษณ์จากมุมมองของ UI แล้ว ไม่มีปัญหาจนถึงตอนนี้ แต่บางคนที่ทำงานในโครงการนี้ก็ตัดสินใจทันทีว่ามีการกระทำเฉพาะที่ต้องการข้อมูลเพิ่มเติมในAction
วัตถุ ด้วยเหตุผลอะไรที่เคย ที่สามารถแก้ไขได้ด้วยการจับแลมบ์ดา ตัวอย่างนี้ไม่ได้นำมา 1-1 จากรหัส
ดังนั้นคนที่แต่งตัวประหลาดมาจากAction
เพื่อเพิ่มรสชาติของเขาเอง
เขาส่งตัวอย่างของชั้นเรียนที่บ้านของเขาไปยังโปรแกรมpush_back
แต่ก็ยุ่งเหยิง
แล้วเกิดอะไรขึ้น?
อย่างที่คุณอาจเดาได้: วัตถุถูกตัดออก
ข้อมูลพิเศษจากอินสแตนซ์หายไปและf
ขณะนี้มีแนวโน้มที่จะมีพฤติกรรมที่ไม่ได้กำหนด
ฉันหวังว่าตัวอย่างนี้นำเกี่ยวกับแสงสำหรับคนผู้ที่ไม่สามารถจริงๆจินตนาการสิ่งที่เมื่อพูดถึงA
และB
s ถูกมาในลักษณะบาง