Tôi nghĩ rằng tôi hiểu những hạn chế thực tế của đa hình thời gian biên dịch và đa hình thời gian chạy. Nhưng sự khác biệt về khái niệm giữa các giao diện rõ ràng (đa hình thời gian chạy. Tức là các hàm ảo và các con trỏ / tham chiếu) và các giao diện ẩn (đa hình thời gian biên dịch. Ví dụ: các mẫu) .
Tôi nghĩ rằng hai đối tượng cung cấp cùng một giao diện rõ ràng phải là cùng một loại đối tượng (hoặc có chung một tổ tiên), trong khi hai đối tượng cung cấp cùng một giao diện ngầm không cần phải là cùng một loại đối tượng và loại trừ ẩn giao diện mà cả hai cung cấp, có thể có chức năng khá khác nhau.
Bất kỳ suy nghĩ về điều này?
Và nếu hai đối tượng cung cấp cùng một giao diện ngầm, thì lý do gì (bên cạnh lợi ích kỹ thuật của việc không cần gửi công văn động với bảng tra cứu chức năng ảo, v.v.) sẽ không có các đối tượng này kế thừa từ một đối tượng cơ sở khai báo giao diện đó, do đó làm cho nó một giao diện rõ ràng ? Một cách khác để nói: bạn có thể cho tôi một trường hợp trong đó hai đối tượng cung cấp cùng một giao diện ẩn (và do đó có thể được sử dụng làm kiểu cho lớp mẫu mẫu) không nên kế thừa từ một lớp cơ sở làm cho giao diện đó rõ ràng không?
Một số bài viết liên quan:
- https://stackoverflow.com/a/7264550/635125
- https://stackoverflow.com/a/7264689/635125
- https://stackoverflow.com/a/8009872/635125
Đây là một ví dụ để làm cho câu hỏi này cụ thể hơn:
Giao diện ngầm định:
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();
}
};
Giao diện rõ ràng:
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();
}
};
Một ví dụ cụ thể hơn, sâu hơn:
Một số vấn đề C ++ có thể được giải quyết bằng một trong hai cách sau:
- một lớp templated có kiểu mẫu cung cấp một giao diện ngầm
- một lớp không có templated có một con trỏ lớp cơ sở cung cấp một giao diện rõ ràng
Mã không thay đổi:
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 */ }
};
Trường hợp 1 . Một lớp không có templated có một con trỏ lớp cơ sở cung cấp một giao diện rõ ràng:
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;
}
Trường hợp 2 . Một lớp templated có kiểu mẫu cung cấp một giao diện ngầm:
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;
}
Trường hợp 3 . Một lớp templated có kiểu mẫu cung cấp một giao diện ẩn (lần này, không xuất phát từ 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;
}
Trường hợp 1 yêu cầu đối tượng được truyền vào phải useCoolClass()
là con của CoolClass
(và hiện thực worthless()
). Trường hợp 2 và 3, mặt khác, sẽ lấy bất kỳ lớp nào có doSomethingCool()
chức năng.
Nếu người dùng mã luôn luôn được phân lớp tốt CoolClass
, thì Trường hợp 1 có ý nghĩa trực quan, vì họ CoolClassUser
sẽ luôn mong đợi việc thực hiện a CoolClass
. Nhưng giả sử mã này sẽ là một phần của khung API, vì vậy tôi không thể dự đoán liệu người dùng có muốn phân lớp CoolClass
hoặc cuộn lớp riêng của họ có doSomethingCool()
chức năng hay không.