ฉันคิดว่าฉันเข้าใจข้อ จำกัด ที่แท้จริงของการรวบรวมความแตกต่างของเวลาและความหลากหลายของเวลาทำงาน แต่อะไรคือความแตกต่างทางแนวคิดระหว่างอินเตอร์เฟสที่ชัดเจน (polymorphism แบบรันไทม์คือฟังก์ชันเสมือนและพอยน์เตอร์ / การอ้างอิง) และอินเทอร์เฟซโดยปริยาย (polymorphism เวลาคอมไพล์เช่น .
ความคิดของฉันคือวัตถุสองชิ้นที่มีส่วนต่อประสานที่ชัดเจนเหมือนกันจะต้องเป็นวัตถุประเภทเดียวกัน (หรือมีบรรพบุรุษร่วมกัน) ในขณะที่วัตถุสองชิ้นที่มีส่วนต่อประสานแบบเดียวกันนั้นไม่จำเป็นต้องเป็นวัตถุชนิดเดียวกัน อินเทอร์เฟซที่พวกเขาทั้งสองเสนอสามารถมีฟังก์ชันการทำงานที่แตกต่างกันมาก
ความคิดใด ๆ เกี่ยวกับเรื่องนี้?
และหากวัตถุสองชิ้นมีอินเตอร์เฟสแบบนัยเดียวกันเหตุผลอะไร (ข้างๆประโยชน์ทางเทคนิคของการไม่ต้องใช้การส่งข้อมูลแบบไดนามิกที่มีตารางการค้นหาฟังก์ชั่นเสมือน ฯลฯ ) จะไม่มีวัตถุเหล่านี้สืบทอดมาจากวัตถุพื้นฐานที่ประกาศอินเตอร์เฟสนั้น ทำให้เป็นอินเทอร์เฟซที่ชัดเจนหรือไม่ อีกวิธีในการบอกว่า: คุณสามารถให้กรณีที่วัตถุสองอย่างที่เสนออินเทอร์เฟซแบบเดียวกัน (และสามารถใช้เป็นชนิดของคลาสเทมเพลตตัวอย่าง) ไม่ควรสืบทอดมาจากคลาสพื้นฐานที่ทำให้อินเทอร์เฟซนั้นชัดเจน?
บางโพสต์ที่เกี่ยวข้อง:
- https://stackoverflow.com/a/7264550/635125
- https://stackoverflow.com/a/7264689/635125
- https://stackoverflow.com/a/8009872/635125
นี่คือตัวอย่างที่จะทำให้คำถามนี้เป็นรูปธรรมมากขึ้น:
การเชื่อมต่อโดยนัย:
class Class1
{
public:
void interfaceFunc();
void otherFunc1();
};
class Class2
{
public:
void interfaceFunc();
void otherFunc2();
};
template <typename T>
class UseClass
{
public:
void run(T & obj)
{
obj.interfaceFunc();
}
};
อินเตอร์เฟซที่ชัดเจน:
class InterfaceClass
{
public:
virtual void interfaceFunc() = 0;
};
class Class1 : public InterfaceClass
{
public:
virtual void interfaceFunc();
void otherFunc1();
};
class Class2 : public InterfaceClass
{
public:
virtual void interfaceFunc();
void otherFunc2();
};
class UseClass
{
public:
void run(InterfaceClass & obj)
{
obj.interfaceFunc();
}
};
ตัวอย่างที่เป็นรูปธรรมในเชิงลึกยิ่งขึ้น:
ปัญหา C ++ บางอย่างสามารถแก้ไขได้ด้วย:
- คลาส templated ที่มีประเภทเทมเพลตจัดเตรียมอินเตอร์เฟส
- คลาสที่ไม่ใช่เท็มเพลตที่ใช้ตัวชี้คลาสเบสซึ่งจัดเตรียมอินเตอร์เฟสที่ชัดเจน
รหัสที่ไม่เปลี่ยนแปลง:
class CoolClass
{
public:
virtual void doSomethingCool() = 0;
virtual void worthless() = 0;
};
class CoolA : public CoolClass
{
public:
virtual void doSomethingCool()
{ /* Do cool stuff that an A would do */ }
virtual void worthless()
{ /* Worthless, but must be implemented */ }
};
class CoolB : public CoolClass
{
public:
virtual void doSomethingCool()
{ /* Do cool stuff that a B would do */ }
virtual void worthless()
{ /* Worthless, but must be implemented */ }
};
กรณีที่ 1 คลาสที่ไม่ใช่เท็มเพลตที่ใช้ตัวชี้คลาสเบสซึ่งจัดเตรียมอินเตอร์เฟสที่ชัดเจน:
class CoolClassUser
{
public:
void useCoolClass(CoolClass * coolClass)
{ coolClass.doSomethingCool(); }
};
int main()
{
CoolA * c1 = new CoolClass;
CoolB * c2 = new CoolClass;
CoolClassUser user;
user.useCoolClass(c1);
user.useCoolClass(c2);
return 0;
}
กรณีที่ 2 คลาสที่มีเทมเพลตซึ่งมีประเภทเทมเพลตจัดเตรียมอินเตอร์เฟสโดยนัย:
template <typename T>
class CoolClassUser
{
public:
void useCoolClass(T * coolClass)
{ coolClass->doSomethingCool(); }
};
int main()
{
CoolA * c1 = new CoolClass;
CoolB * c2 = new CoolClass;
CoolClassUser<CoolClass> user;
user.useCoolClass(c1);
user.useCoolClass(c2);
return 0;
}
กรณีที่ 3 คลาสที่มีเทมเพลตซึ่งมีประเภทเทมเพลตจัดเตรียมอินเทอร์เฟซโดยนัย (ในเวลานี้ไม่ใช่ที่มาจากCoolClass
:
class RandomClass
{
public:
void doSomethingCool()
{ /* Do cool stuff that a RandomClass would do */ }
// I don't have to implement worthless()! Na na na na na!
}
template <typename T>
class CoolClassUser
{
public:
void useCoolClass(T * coolClass)
{ coolClass->doSomethingCool(); }
};
int main()
{
RandomClass * c1 = new RandomClass;
RandomClass * c2 = new RandomClass;
CoolClassUser<RandomClass> user;
user.useCoolClass(c1);
user.useCoolClass(c2);
return 0;
}
กรณีที่ 1 ต้องการให้วัตถุที่ถูกส่งผ่านเข้าuseCoolClass()
มาเป็นลูกของCoolClass
(และนำไปใช้worthless()
) ในกรณีที่ 2 และ 3 จะใช้คลาสใดก็ได้ที่มีdoSomethingCool()
ฟังก์ชั่น
หากผู้ใช้รหัสเป็นซับคลาสคลาสที่ดีอยู่เสมอCoolClass
ดังนั้นกรณีที่ 1 ทำให้เข้าใจได้ง่ายเนื่องจากผู้ใช้CoolClassUser
จะคาดหวังว่าจะนำ a CoolClass
ไปใช้ แต่สมมติว่ารหัสนี้จะเป็นส่วนหนึ่งของกรอบงาน API ดังนั้นฉันไม่สามารถคาดการณ์ได้ว่าผู้ใช้จะต้องการคลาสย่อยCoolClass
หรือหมุนคลาสของตัวเองที่มีdoSomethingCool()
ฟังก์ชั่น