2011-12-30 27 views
77

lẽ là một bản sao, nhưng không phải một điều dễ dàng để tìm kiếm ...cách chính xác để xác định C++ phương pháp namespace trong tập tin cpp

Cho một tiêu đề như:

namespace ns1 
{ 
class MyClass 
{ 
    void method(); 
}; 
} 

Tôi đã thấy method() định nghĩa theo nhiều cách trong file cpp:

Phiên bản 1:

namespace ns1 
{ 
void MyClass::method() 
{ 
    ... 
} 
} 

Vers ion 2:

using namespace ns1; 

void MyClass::method() 
{ 
... 
} 

Phiên bản 3:

void ns1::MyClass::method() 
{ 
... 
} 

Có một 'đúng' cách để làm điều đó? Có bất kỳ 'sai' nào ở chỗ chúng không có nghĩa là giống nhau không?

+0

Trong hầu hết các mã Tôi thường thấy phiên bản thứ ba (nhưng tôi không lý do tại sao: D), phiên bản thứ hai chỉ đơn giản là đối diện với lý do tại sao không gian tên được giới thiệu tôi đoán. –

+1

Như trong thực tế thú vị, các công cụ tái cấu trúc Visual Assist rất vui khi tạo mã bằng cách sử dụng # 1 hoặC# 3, tùy thuộc vào kiểu nào đã được sử dụng trong tệp đích. –

Trả lời

36

Phiên bản 2 là không rõ ràng và không dễ hiểu bởi vì bạn không biết được namespace MyClass thuộc về và nó chỉ là vô lý (chức năng lớp không trong không gian tên giống nhau không?)

Phiên bản 1 là đúng bởi vì nó cho thấy rằng trong không gian tên, bạn đang định nghĩa hàm.

Phiên bản 3 cũng đúng vì bạn đã sử dụng toán tử phân giải phạm vi :: để tham chiếu đến MyClass::method() trong không gian tên ns1. Tôi thích phiên bản 3.

Xem Namespaces (C++). Đây là cách tốt nhất để làm điều này.

+0

bạn có thể xây dựng điều gì sai với phiên bản 2 không? –

+13

Gọi # 2 "sai" là một cường điệu lớn. Theo logic này, tất cả các tên biểu tượng là "sai" vì chúng có khả năng ẩn các tên biểu tượng khác trong phạm vi khác. – tenfour

+0

Đó là phi lý. Nó sẽ biên dịch tốt (xin lỗi, misexplained rằng trong câu trả lời), nhưng tại sao bạn sẽ xác định một chức năng bên ngoài không gian tên của nó? Nó gây nhầm lẫn cho người đọc. Ngoài ra, khi nhiều không gian tên được sử dụng, nó không hiển thị không gian tên MyClass thuộc về. Phiên bản 1 & 3 khắc phục sự cố này. Tóm lại, nó không sai, nhưng không rõ ràng và khó hiểu. – GILGAMESH

4

Phiên bản 3 làm cho liên kết giữa lớp và không gian tên rất rõ ràng với chi phí nhập nhiều hơn. Phiên bản 1 tránh điều này nhưng bắt giữ liên kết với một khối. Phiên bản 2 có xu hướng ẩn này vì vậy tôi muốn tránh điều đó.

2

Tất cả các cách đều đúng và mỗi cách đều có những ưu điểm và nhược điểm của nó.

Trong phiên bản 1, bạn có lợi thế là không phải viết không gian tên ở trước mỗi chức năng. Điểm bất lợi là bạn sẽ nhận được một định danh nhàm chán, đặc biệt nếu bạn có nhiều hơn một mức không gian tên. Trong phiên bản 2, bạn làm cho mã của bạn sạch hơn, nhưng nếu bạn có nhiều hơn một không gian tên đang được triển khai trong CPP, bạn có thể truy cập trực tiếp vào các chức năng và biến của người khác, làm cho không gian tên của bạn vô dụng (đối với tệp cpp đó).

Trong phiên bản 3, bạn sẽ phải nhập nhiều hơn và các dòng chức năng của bạn có thể lớn hơn màn hình, điều này không tốt cho hiệu ứng thiết kế.

Ngoài ra còn có một cách khác mà một số người sử dụng. Nó tương tự như phiên bản đầu tiên, nhưng không có vấn đề về định danh.

Đó là như thế này:

#define OPEN_NS1 namespace ns1 { 
#define CLOSE_NS1 } 

OPEN_NS1 

void MyClass::method() 
{ 
... 
} 

CLOSE_NS1 

Đó là tùy thuộc vào bạn để chọn cái nào là tốt hơn cho từng tình huống =]

+12

Tôi không thấy bất kỳ lý do nào để sử dụng macro ở đây. Nếu bạn không muốn thụt lề, chỉ cần không thụt lề. Sử dụng macro chỉ làm cho mã ít rõ ràng hơn. – tenfour

+1

Tôi nghĩ rằng phiên bản cuối cùng bạn đề cập là hữu ích bất cứ khi nào bạn muốn biên dịch mã với các trình biên dịch cũ không hỗ trợ không gian tên (Có, một số loài khủng long vẫn còn ở xung quanh). Trong trường hợp đó, bạn có thể đặt macro bên trong một mệnh đề '# ifdef'. –

+0

Bạn không cần phải nhận dạng nếu bạn không muốn, nhưng nếu bạn không sử dụng macro, một số IDE sẽ cố gắng làm điều đó cho bạn. Ví dụ: trong Visual Studio, bạn có thể chọn toàn bộ mã và nhấn ALT + F8 để tự động nhận dạng. Nếu bạn không sử dụng định nghĩa, bạn sẽ mất chức năng đó. Ngoài ra, tôi không nghĩ rằng OPEN_ (không gian tên) và CLOSE_ (không gian tên) là ít rõ ràng hơn, nếu bạn có nó trong tiêu chuẩn mã hóa của bạn. Lý do @LucaMartini đưa ra cũng thú vị. –

1

tôi chọn Num.3 (còn gọi là phiên bản tiết). Đó là gõ nhiều hơn, nhưng ý định là chính xác cho bạn và trình biên dịch.Vấn đề bạn đăng là thực sự đơn giản hơn thế giới thực. Trong thế giới thực, có những phạm vi khác cho các định nghĩa, không chỉ các thành viên lớp học. Định nghĩa của bạn không chỉ phức tạp với các lớp - vì phạm vi của chúng chưa bao giờ được mở lại (không giống như các không gian tên, phạm vi toàn cục, v.v.).

Num.1 điều này có thể không thành công với các phạm vi khác ngoài các lớp - mọi thứ có thể được mở lại. Vì vậy, bạn có thể khai báo một hàm mới trong một không gian tên bằng cách sử dụng cách tiếp cận này, hoặc các nội tuyến của bạn có thể được thay thế bằng ODR. Bạn sẽ cần điều này cho một số định nghĩa (đáng chú ý là các chuyên ngành mẫu).

Num.2 Điều này rất mong manh, đặc biệt là trong các mã lớn - như tiêu đề và sự thay đổi phụ thuộc, chương trình của bạn sẽ không biên dịch được.

Num.3 Đây là lý tưởng, nhưng rất nhiều để nhập - ý định của bạn là xác định một cái gì đó. Điều này thực hiện chính xác điều đó và trình biên dịch khởi động để đảm bảo bạn không mắc lỗi, định nghĩa không đồng bộ với khai báo của nó, v.v.

12

Tôi đang sử dụng phiên bản 4 (bên dưới) vì nó kết hợp hầu hết các ưu điểm của phiên bản 1 (độ nhạy của định nghĩa resoective) và phiên bản 3 (tối đa là rõ ràng). Những bất lợi chính là mọi người không quen với nó nhưng vì tôi xem xét nó kỹ thuật vượt trội so với các lựa chọn thay thế tôi không nhớ.

Version 4: sử dụng đủ điều kiện sử dụng bí danh namespace:

#include "my-header.hpp" 
namespace OI = outer::inner; 
void OI::Obj::method() { 
    ... 
} 

Trong thế giới của tôi, tôi đang thường xuyên sử dụng bí danh namespace như tất cả mọi thứ một cách rõ ràng là có trình độ - trừ khi nó có thể không (ví dụ như tên biến) hoặc nó là một điểm tùy biến đã biết (ví dụ swap() trong một mẫu hàm).

+1

Trong khi tôi nghĩ rằng "nó tốt hơn vì vậy tôi không quan tâm nếu nó confuses người" logic là thiếu sót, tôi phải đồng ý này _is_ một cách tiếp cận tốt cho không gian tên lồng nhau. –

+1

+1 cho ý tưởng "lý do tại sao tôi không nghĩ đến điều đó" tuyệt vời! (Đối với "những người không quen với [những thứ cao cấp về công nghệ mới]", họ sẽ quen với nó nếu có nhiều người làm điều đó.) – wjl

3

Hóa ra nó không chỉ là "vấn đề kiểu mã hóa". Số. 2 dẫn đến lỗi liên kết khi xác định và khởi tạo biến được khai báo bên ngoài trong tệp tiêu đề. Hãy xem ví dụ trong câu hỏi của tôi. Definition of constant within namespace in cpp file

13

5 năm sau đó và tôi nghĩ rằng tôi muốn đề cập đến điều này, mà cả hai có vẻ tốt đẹp và không phải là ác

using ns1::MyClass; 

void MyClass::method() 
{ 
    // ... 
} 
+0

Đây là câu trả lời hay nhất. Nó trông sạch sẽ nhất, và tránh các vấn đề với các Phiên bản 1 của OP, có thể đưa mọi thứ vào không gian tên một cách vô ý, và 2, có thể đưa mọi thứ vào không gian toàn cầu một cách vô tình. –

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