2011-02-03 23 views
5

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?

+0

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

+0

@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

+1

@sharptooth nhưng đó không phải là một câu hỏi, phải không? – tenpn

Trả lời

2

This FAQ item tổng hợp mọi thứ về lý do tại sao c-phôi xấu.

Bất kỳ diễn viên c nào đều có tiềm năng là bom, vì họ đang ẩn cảnh báo chuyển đổi và lỗi bằng cách tắt tiếng trình biên dịch.

Vì bạn muốn một ví dụ, ở đây là:

int main() 
{ 
    float a = 0.123; 
    double *b = (double*) &a; 
    *b = 0.123; 
} 
+0

mục Câu hỏi thường gặp tốt, nhưng đó là về phôi nói chung, không phải về C-phôi đặc biệt. – sharptooth

+0

@sharptooth Tôi đoán bạn đã đúng. Tuy nhiên, mọi hướng dẫn phong cách mã hóa C++ phong nha sẽ cho bạn biết không sử dụng phôi kiểu c. –

1

Một ví dụ rất đơn giản:

class ClassB;//only forward declaration, no real declaration included 

Class A * a; 
Class B * b; 
a = (ClassA *)b; 

Dàn diễn viên sẽ luôn âm thầm thành công nếu chỉ có tờ khai chuyển tiếp của ClassB. Nó không quan tâm nếu ClassB có nguồn gốc từ ClassA. Và cũng sẽ sai khi ClassB không chỉ bắt nguồn từ ClassA:

class ClassB:public SomeOtherClass, public ClassA {}; 
Các vấn đề liên quan