2015-02-15 17 views
5
#include <iostream> 
using namespace std; 

#include "other_library.h" 

struct Foo 
{ 
    Foo() { cout << "class\n"; } 
}; 

int main() 
{ 
    Foo(); // or Foo() in any expression 
} 

Kết quả đầu ra này class, hoặc vì vậy chúng tôi nghĩ. Vấn đề là nếu other_library.h xảy ra để có một chức năng gọi là Foo mà trở lại loại phù hợp để xuất hiện trong bất cứ biểu chúng tôi sử dụng Foo trong sau đó nó âm thầm thay đổi hành vi, ví dụ:Chống lại sự nguy hiểm của tên lớp ẩn tên chức năng

int Foo() { cout << "func\n"; return 1; } 

nguyên nhân func là đầu ra mà không cần bất kỳ mã thay đổi trong main. Điều này là xấu vì khả năng cho các lỗi phát hiện và khó phát hiện; ngay cả khi nó không phải là ý định độc hại trên một phần của other_library, một cuộc đụng độ tên có thể không bị phát hiện.


Cách tốt nhất để giải quyết vấn đề này là gì? Ban đầu nó được nuôi dưỡng bởi Dan Saks in 1997, và one suggested resolutiontất cả lớp nên được typedef'd:

typedef struct Foo Foo; 

như trình biên dịch không phải báo cáo một vụ đụng độ giữa một typedef tên và một tên hàm . Tuy nhiên điều này dường như không phổ biến - tại sao không?

Làm rõ: câu hỏi này là về các phương pháp hay để mã của chúng tôi ngừng thay đổi hành vi không bị phát hiện này xảy ra mà chúng tôi không nhận thấy. (Trái ngược với cách giải quyết nó khi chúng tôi nhận ra rằng điều đó đang xảy ra, điều này dễ dàng hơn - ví dụ: đổi tên lớp của chúng tôi).

+0

Namespaces và Vệ sinh mã tốt là phương pháp ưa thích của tôi. – BlamKiwi

+0

@MorphingDragon Tôi đoán vấn đề là những gì sẽ xảy ra khi bạn sử dụng mã cũ không nằm trong một không gian tên (như 'other_library.h' ở đây). Ngay cả khi bạn đặt mã của riêng bạn bên trong một không gian tên, bạn vẫn gặp rắc rối nếu làm việc bên trong không gian tên (hoặc 'sử dụng' nó). – vsoftco

+0

Những gì tôi đã thấy là chức năng đặt tên với camelCase và các kiểu với CapitalCamelCase. Không có xung đột. – Quentin

Trả lời

4

typedef struct Foo Foo;

như trình biên dịch không phải báo cáo một vụ đụng độ giữa một typedef tên và một tên hàm. Tuy nhiên, điều này dường như không phổ biến - tại sao không?

Tôi giữ sự thật này là hiển nhiên: mã cồng kềnh rườm rà. Bạn thực sự có thể dễ dàng sửa lỗi này bằng cách làm việc trong một không gian tên của chính bạn (trong đó, giả sử tập tin tiêu đề là C++, cũng vậy,

3

Thật không may, bạn không thể tránh điều này. (3.3.10):

Tên lớp (9.1) hoặc tên liệt kê (7.2) có thể được ẩn bằng tên của biến, thành viên dữ liệu, hàm hoặc điều tra được khai báo trong cùng một phạm vi. hoặc tên điều tra và biến, thành viên dữ liệu, hàm hoặc điều tra được khai báo trong cùng một phạm vi (theo thứ tự bất kỳ) có cùng tên, tên lớp hoặc liệt kê được ẩn ở bất kỳ nơi nào, biến, thành viên dữ liệu, hàm hoặc tên điều tra hiển thị

Cách duy nhất để bảo vệ chống lại nó là mẹo typedef bạn đã chỉ ra (cảm ơn điều đó!), Sử dụng không gian tên hoặc tôn trọng quy ước đặt tên (không hỗ trợ khi xử lý mã bên thứ 3). Bạn cũng có thể thử bọc phần bao gồm trong một không gian tên (được hiển thị dưới đây), nhưng như các chú thích đã chỉ ra, điều này có thể gây ra các lỗi liên kết trong một số tình huống nhất định.

namespace otherlib { 
#include "other_library.h" 
} 

Sau đó:

otherlib::Foo(); 
+0

Điều này có thể không gây ra các vấn đề liên kết không? Về cơ bản, bạn đang thay đổi tất cả tên của mọi biểu tượng trong 'other_library.h'. – BlamKiwi

+3

Tôi nghĩ rằng điều này sẽ gây ra lỗi liên kết (trừ khi bạn muốn biên dịch lại tất cả 'otherlib' cũng có trong không gian tên), và cũng có thể gây thêm lỗi nếu' other_library.h' thực hiện bất kỳ '# include' nào s –

+0

Có, nó có khả năng gây ra lỗi liên kết. Tất cả phụ thuộc vào tệp được bao gồm. Khác với lừa typedef, tôi không nghĩ rằng có một cách để coi đây là một lỗi. Ngay cả cố gắng -Weverything trong clang và nó vẫn biên dịch. Cảm ơn '' C'' cho rằng – Rado

1

thực hành tốt nhất hiện nay bảo vệ chống lại điều này đã

  • ước đặt tên, chẳng hạn như
    void camelCase() vs class PascalCase

  • namespace

  • libs wrapper cho tất cả mọi thứ không hiện đại C++

+0

Bạn làm gì khi bạn phải sử dụng một thư viện không phù hợp với các quy ước này? (ví dụ: hầu hết trong số họ hoặc khi bạn liên kết với thư viện được triển khai trong C) –

+0

trình bao bọc mỏng để làm cho nó phù hợp, với tiêu đề thường không để lộ bất kỳ thứ gì của nội bộ – sp2danny

+0

Nhược điểm, thêm thư viện mới vào danh sách được phê duyệt, có một số công việc cho nó (và một số quan liêu). Có lẽ 'thực hành tốt nhất hiện nay' nên là 'những gì chúng tôi làm' – sp2danny

Các vấn đề liên quan