C ++: Không gian tên - Làm thế nào để sử dụng đúng cách trong tệp tiêu đề và tệp nguồn?


88

Hãy xem xét một cặp hai tệp nguồn: tệp khai báo giao diện ( *.hhoặc *.hpp) và tệp thực thi của nó ( *.cpp).

Hãy để *.htệp giống như sau:

namespace MyNamespace {
  class MyClass {
  public:
    int foo();
  };
}

Tôi đã thấy hai phương pháp khác nhau để sử dụng không gian tên trong tệp nguồn:

*.cpp hiển thị thực hành # 1:

#include "MyClass.h"
using namespace MyNamespace;

int MyClass::foo() { ... }

*.cpp hiển thị thực hành # 2:

#include "MyClass.h"
namespace MyNamespace {

  int MyClass::foo() { ... }

}

Câu hỏi của tôi: Có sự khác biệt nào giữa hai phương pháp này và một phương pháp được coi là tốt hơn phương pháp kia không?


30
Ngoài ra còn có tùy chọn 3: Chỉ chúng tôi tên đầy đủ, ví dụ int MyNamespace::MyClass::foo() ....
Benjamin Bannier

1
Có thể trùng lặp: stackoverflow.com/questions/7789163/…
David

@ Lưu không trùng lặp. Những câu hỏi này bổ sung cho nhau. Đề nghị thêm liên kết do Dave cung cấp là "Đọc thêm ..." cho câu hỏi này. Câu hỏi của tôi sẽ giúp người mới chọn phong cách chính xác.
nickolay

Câu trả lời:


62

Từ quan điểm về khả năng đọc mã, theo tôi có lẽ tốt hơn nên sử dụng phương pháp số 2 vì lý do này:

Bạn có thể có usingnhiều không gian tên cùng một lúc và bất kỳ đối tượng hoặc chức năng nào được viết bên dưới dòng đó đều có thể thuộc về bất kỳ không gian tên nào trong số các không gian tên đó (cấm xung đột đặt tên). Gói toàn bộ tệp trong một namespacekhối rõ ràng hơn và cho phép bạn khai báo các hàm và biến mới thuộc không gian tên đó trong tệp .cpp.


Câu hỏi mà Dave liên kết trong bình luận của anh ấy với câu hỏi của bạn cũng nêu ra một số điểm chính về sự khác biệt (nếu có) giữa hai phương pháp mà bạn đang xem xét
Dan F

Các bạn, tôi thực sự không biết chọn câu trả lời của ai. Chúng có sự giao nhau trong khi bổ sung cho nhau.
nickolay

Chỉ cần bình luận để thừa nhận rằng một số IDE như CLion sẽ chỉ phát hiện các triển khai nếu bạn sử dụng tùy chọn / thực hành # 2.
PedroTanaka

@PedroTanaka vẫn còn trường hợp này chứ? Tôi đã không nhận thấy bất kỳ vấn đề như vậy.
John McFarlane

@JMcF Tôi đã không kiểm tra kể từ thời điểm tôi đăng nhận xét. Trong các phiên bản đầu tiên của Clion, sự cố đã xảy ra.
PedroTanaka

51

Rõ ràng nhất là tùy chọn bạn không hiển thị:

int MyNamespace::MyClass::foo()
{
    //  ...
}

Nó cũng rất dài dòng; quá nhiều đối với hầu hết mọi người. Theo using namespacekinh nghiệm của tôi, vì đây là một khoản thu cho xung đột tên, và nên tránh ngoại trừ trong phạm vi và địa điểm rất hạn chế, tôi thường sử dụng số 2 của bạn.


3
Cảm ơn rất rõ ràng. Chúng tôi đã cùng nhau tạo một trang Câu hỏi thường gặp tốt cho người dùng không gian tên. :)
nickolay

2
Các bạn, tôi thực sự không biết chọn câu trả lời của ai. Chúng có sự giao nhau trong khi bổ sung cho nhau.
nickolay

10

Có sự khác biệt nào giữa hai cách làm này không

Đúng. # 1 và # 2 là các ví dụ về cách sử dụng chỉ thịđịnh nghĩa vùng tên tương ứng. Chúng có hiệu quả như nhau trong trường hợp này nhưng có những hậu quả khác. Ví dụ: nếu bạn giới thiệu một số nhận dạng mới cùng với MyClass::foo, nó sẽ có một phạm vi khác:

# 1:

using namespace MyNamespace;
int x;  // defines ::x

# 2:

namespace MyNamespace {
  int x;  // defines MyNamespace::x
}

cái này được coi là tốt hơn cái kia?

# 1 Ưu điểm: ngắn gọn hơn một chút; khó hơn vô tình giới thiệu một cái gì đó vào một cách MyNamespacekhông cố ý. Nhược điểm: có thể vô tình kéo các số nhận dạng hiện có vào.

# 2 Ưu điểm: rõ ràng hơn là cả hai định nghĩa về số nhận dạng hiện có và khai báo của số nhận dạng mới đều thuộc về MyNamespace. Nhược điểm: dễ vô tình giới thiệu số nhận dạng MyNamespace.

Một chỉ trích đối với cả # 1 và # 2 là chúng đang đề cập đến toàn bộ không gian tên khi bạn có thể chỉ quan tâm đến định nghĩa của các thành viên trong đó MyNamespace::MyClass. Điều này là nặng tay và nó truyền đạt ý định kém.

Một giải pháp thay thế có thể có cho # 1 là khai báo sử dụng chỉ bao gồm số nhận dạng mà bạn quan tâm:

#include "MyClass.h"
using MyNamespace::MyClass;

int MyClass::foo() { ... }

4

Tôi cũng muốn nói thêm rằng nếu vì lý do nào đó bạn quyết định triển khai chuyên môn hóa mẫu trong tệp cpp và chỉ cần dựa vào using namespacebạn sẽ gặp phải sự cố sau:

// .h file
namespace someNameSpace
{
  template<typename T>
    class Demo
    {
      void foo();
    };
}

// .cpp file
using namespace someNameSpace;

template<typename T>
void Demo<T>::foo(){}

// this will produce
// error: specialization of 'template<class T> void someNameSpace::Demo<T>::foo()' in different namespace [-fpermissive]
template<>
void Demo<int>::foo(){}

Ngược lại, nếu bạn áp dụng phương pháp số 2, điều này sẽ ổn.


0

Tôi muốn thêm một cách nữa, bằng cách sử dụng khai báo :

#include "MyClass.h"
using MyNamespace::MyClass;

int MyClass::foo() { ... }

Cách này giúp bạn không phải gõ tên không gian tên nhiều lần nếu lớp có nhiều hàm

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.