Phạm vi của khai báo “using” trong C ++ là gì?


100

Tôi đang sử dụng khai báo 'using' trong C ++ để thêm std :: string và std :: vector vào không gian tên cục bộ (để tiết kiệm việc nhập 'std ::' s không cần thiết).

using std::string;
using std::vector;

class Foo { /*...*/ };

Phạm vi trên khai báo này là gì? Nếu tôi thực hiện điều này trong tiêu đề, nó có đưa các khai báo 'sử dụng' này vào mọi tệp cpp bao gồm tiêu đề không?


18
Đề phòng trường hợp nó không rõ ràng từ các câu trả lời khác ở đây: - Không đặt một usingkhai báo (hoặc usingchỉ thị) ở phạm vi tệp trong tệp / tiêu đề bao gồm! Điều đó sẽ gây đau đầu cho những người sử dụng tiêu đề.
Michael Burr

Trong thực tế, không đặt một usingtuyên bố (a fortiori chỉ thị ) trong một tiêu đề ở tất cả , thậm chí trong một không gian tên! Xem phạm vi sử dụng khai báo trong một không gian tên để biết các vấn đề này gây ra.
Nils von Barth

@NilsvonBarth: Đó là đơn giản hóa một chút. Sử dụng usingtrong phạm vi lớp và chức năng là an toàn liên quan đến vấn đề đã thảo luận.
Sebastian Mach


Bạn có thể quan tâm để đọc về tính năng tra cứu ADL C ++ .
Alexis Wilke

Câu trả lời:


59

Khi bạn #include tệp tiêu đề trong C ++, nó sẽ đặt toàn bộ nội dung của tệp tiêu đề vào vị trí mà bạn đã đưa nó vào tệp nguồn. Vì vậy, bao gồm một tệp có usingkhai báo có tác dụng chính xác như đặt usingkhai báo ở đầu mỗi tệp bao gồm tệp tiêu đề đó.


51
... mà nói chung là một điều xấu.
Catskul

17
Nhưng nếu bạn đặt usingkhai báo bên trong namespacethì nó bị giới hạn trong phạm vi của không gian tên đó, nói chung là OK (với những lưu ý thông thường về nhu cầu và phong cách cụ thể của bạn).
0

1
... nhưng nếu bạn sử dụng bên trong một không gian tên, hãy đảm bảo rằng bạn không làm điều đó để cố gắng vượt qua một thứ mà bình thường là một ý tưởng tồi, chẳng hạn như bạn không thể mã hóa các phương thức lớp được khai báo bên ngoài không gian tên Y bên trong cái kia không gian tên X, để bạn có thể sử dụng cục bộ không gian tên X. Đó là lý do tại sao chúng ta sử dụng không gian tên :: trình phân giải ngay từ đầu. Nếu vấn đề lớn xảy ra khi nhập, hoặc là macro (có thể dễ dẫn đến mùi mã) hoặc tốt hơn, hãy tách nó thành nguồn .cpp của chính nó, nơi bạn sẽ chỉ sử dụng không gian tên ở đó.
osirisgothra

1
Mặc dù câu trả lời này và các câu trả lời tương tự là lời khuyên tốt, nhưng chúng không trả lời câu hỏi.
Emile Cormier

116

Không có gì đặc biệt về các tệp tiêu đề sẽ giữ cho usingkhai báo không có. Đó là một sự thay thế văn bản đơn giản trước khi quá trình biên dịch bắt đầu.

Bạn có thể giới hạn một using khai báo trong một phạm vi:

void myFunction()
{
   using namespace std; // only applies to the function's scope
   vector<int> myVector;
}

12
Tôi chưa bao giờ nghĩ rằng tôi có thể sử dụng nó bên trong một hàm!
Agostino

1
Tôi có một loạt các không gian tên đều được sử dụng bởi một tệp kiểu "conglomerator" và thử nghiệm đơn vị gmock cực kỳ tẻ nhạt vì mỗi thử nghiệm sử dụng những thứ từ một không gian tên cụ thể và tôi nghĩ mình phải đủ điều kiện cho từng biến. Sử dụng usingbên trong một hàm (hoặc thậm chí một TESTmacro gtest !) Làm cho cuộc sống của tôi tốt hơn rất nhiều!
dwanderson

54

Phạm vi của câu lệnh using phụ thuộc vào vị trí của nó trong mã:

  • Được đặt ở đầu tệp, nó có phạm vi trong toàn bộ tệp đó.
  • Nếu đây là tệp tiêu đề, nó sẽ có phạm vi trong tất cả các tệp bao gồm tiêu đề đó. Nói chung, đây " không phải là một ý kiến ​​hay vì nó có thể có những tác dụng phụ không mong muốn
  • Nếu không, câu lệnh using có phạm vi trong khối chứa nó từ thời điểm nó xảy ra cho đến cuối khối. Nếu nó được đặt trong một phương thức, nó sẽ có phạm vi bên trong phương thức đó. Nếu nó được đặt trong một định nghĩa lớp, nó sẽ có phạm vi trong lớp đó.

5
Tôi nghĩ rằng không thể thêm một usingcâu lệnh trong phạm vi lớp ...? Tôi đã có cùng một câu hỏi với OP vì điều đó là tôi muốn tránh đánh máy std::khắp nơi. Tôi nhận được các lớp sử dụng rất nhiều vectơ với con trỏ thông minh và std::tiền tố năm ký tự thêm rất nhiều độ dài dòng - điều mà tôi thấy là đọc tệ hơn. Vì vậy, tôi đã tự hỏi liệu một usingchỉ thị trong không gian tên chứa lớp có ổn không? (Thậm chí nếu trong một tiêu đề.)
thomthom

5
Còn nếu nó được đặt trong phạm vi của a namespace { ... }?
einpoklum

Vì vậy, bạn hoàn toàn có thể viết: {using namespace blabla; lớp blah {}; } và việc sử dụng sẽ chỉ áp dụng cho lớp?
Dinaiz

8

Phạm vi là bất kỳ phạm vi nào mà khai báo đang sử dụng nằm trong đó.

Nếu đây là phạm vi toàn cầu, thì nó sẽ ở phạm vi toàn cầu. Nếu nó nằm trong phạm vi chung của tệp tiêu đề, thì nó sẽ nằm trong phạm vi toàn cầu của mọi tệp nguồn bao gồm tiêu đề.

Vì vậy, lời khuyên chung là tránh sử dụng các khai báo trong phạm vi chung của tệp tiêu đề .


3
Điều đó không đủ mạnh. Thay thế tránh bằng Không
Martin York

1
Tránh né mạnh hơn không. "Tránh va vào những chiếc xe khác"
bobobobo

6

Trong trường hợp được trích dẫn, tệp ("đơn vị dịch"), có nghĩa là có, mọi tệp bao gồm nó.

Bạn cũng có thể đặt câu lệnh using bên trong lớp, trong trường hợp đó, nó chỉ có hiệu lực cho lớp đó.

Nói chung, nếu bạn cần chỉ định một không gian tên trong tiêu đề, tốt nhất là chỉ cần xác định đầy đủ mọi định danh cần thiết.


Lưu ý rằng phần usingkhai báo trong một lớp không hoạt động giống như bên ngoài một lớp - ví dụ: bạn không thể sử dụng nó mang lại coutthay vì std::coutvào phạm vi của lớp.
0

2

Đúng rồi. Phạm vi là mô-đun sử dụng usingkhai báo. Nếu bất kỳ tệp tiêu đề nào mà một mô-đun bao gồm có các usingkhai báo, phạm vi của các khai báo đó sẽ là mô-đun đó, cũng như bất kỳ mô-đun nào khác bao gồm các tiêu đề giống nhau.


1

Có một vài nhận xét khá thiếu chuẩn mực khi họ nói "Đừng". Điều đó là quá nghiêm khắc, nhưng bạn phải hiểu khi nào thì được.

Viết using std::stringkhông bao giờ là OK. Viết using ImplementationDetail::Footrong tiêu đề của riêng bạn, khi tiêu đề đó khai báo implementDetail :: Foo có thể được, hơn nữa nếu khai báo sử dụng xảy ra trong không gian tên của bạn. Ví dụ

namespace MyNS {
    namespace ImplementationDetail {
        int Foo;
    }
    using ImplementationDetail::Foo;
}

1
Người sử dụng tiêu đề sau đó có thể viếtMyNS::Foo
Peter Remmers

Một ví dụ tốt hơn là using boost::posix_time::ptime. Chắc chắn người dùng có thể viết MyNS::ptimenhưng đó không phải là ngày tận thế và có thể được bù đắp bởi sự tiện lợi của việc có thể có các chức năng như MyFunction(ptime a, ptime b).
0

5
Tại saousing std::stringkhông bao giờ ok? Ngay cả trong không gian tên của riêng bạn để lưu rất nhiều std::tiền tố?
thomthom

@thomthom sẽ ổn khi được bao bọc trong một phạm vi chẳng hạn như không gian tên của riêng bạn.
jcoffland
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.