Gần đây tôi đã tìm thấy một ví dụ tuyệt vời về lý do tại sao phôi kiểu C là xấu. Chúng tôi bắt đầu với một lớp học sau đây thực hiện nhiều giao diện COM (Tôi có hai cho ngắn gọn, nhưng có thể là mười trong cuộc sống thực):Những ví dụ khắc nghiệt nào cho thấy các phôi kiểu C là xấu?
class CMyClassInitial : public IInterface1, public IInterface2 {
//declarations omitted
};
HRESULT CMyClassInitial::QueryInterface(REFIID iid, void** ppv)
{
if(ppv == 0) {
return E_POINTER;
}
*ppv = 0;
if(iid == __uuidof(IUnknown) || iid == __uuidof(IInterface1)) {
*ppv = (IInterface1*)this;
} else if(iid == __uuidof(IInterface2)) {
*ppv = (IInterface2*)this;
} else {
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
Việc thực hiện trên sử dụng C-phôi cho adjusting pointers to account for multiple inheritance. Chúng thậm chí hoạt động như giá trị con trỏ static_cast
s - this
sẽ được điều chỉnh chính xác.
Bây giờ chúng tôi sao chép-dán (hoặc tôi nên nói sử dụng lại mã?) Cùng một QueryInterface()
triển khai cho một số lớp học tương tự khác.
class CMyClassModified : public IInterface1 {
//declarations omitted
};
và để thực hiện tương tự. Các lớp mới không kế thừa từ IInterface2
nữa nhưng
} else if(iid == __uuidof(IInterface2)) {
*ppv = (IInterface2*)this;
}
sẽ biên dịch tốt và C-style cast sẽ hoạt động như reinterpret_cast
- this
giá trị con trỏ sẽ được sao chép không thay đổi. Người gọi sẽ nhận con trỏ đến đối tượng không thực sự thực hiện IInterface2
- cách thẳng đến hành vi không xác định. Những vấn đề như vậy có thể khó phát hiện trong một cơ sở dữ liệu khổng lồ và khi có nhiều giao diện (không phải như trong ví dụ của tôi).
Nếu static_cast
đã được sử dụng đó sẽ không xảy ra - trình biên dịch sẽ phát ra một lỗi khi cố gắng biên dịch
*ppv = static_cast<IInterface2*>(this);
IMO đó là một ví dụ đủ khắc nghiệt như thế nào sử dụng dàn diễn viên C-phong cách có thể gây ra vấn đề nghiêm trọng.
Có những ví dụ nào khác?
Một lưu ý tuyệt vời, nhưng tôi không hoàn toàn chắc chắn điều này phù hợp với SO. Có vẻ như rất nhiều thảo luận. Tốt nhất là một wiki cộng đồng. – tenpn
@tenpn: Tôi không thấy những gì có thể được thảo luận ở đây - chỉ là một ví dụ về việc tự bắn mình vào chân trong C++. – sharptooth
@sharptooth nhưng đó không phải là một câu hỏi, phải không? – tenpn