C ++ hỗ trợ hai hoán vị trên các không gian tên(namespace) thông thường mà ít nhất chúng ta phải biết. Chúng ta sẽ không xây dựng dựa trên những điều này, vì vậy hãy coi bài học này là tùy chọn.
Nội dung chính
1. Không gian tên không có tên (ẩn danh)
Không gian tên chưa được đặt tên (còn được gọi là không gian tên ẩn danh) là không gian tên được định nghĩa mà không có tên, như sau:
/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/
#include <iostream>
namespace // unnamed namespace
{
void doSomething() // can only be accessed in this file
{
std::cout << "v1\n";
}
}
int main()
{
doSomething(); // we can call doSomething() without a namespace prefix
return 0;
}
Kết quả
v1
Tất cả nội dung được khai báo trong không gian tên chưa được đặt tên được coi như thể nó là một phần của không gian tên gốc. Vì vậy, mặc dù hàm doSomething được định nghĩa trong không gian tên chưa được đặt tên, nhưng bản thân hàm có thể truy cập được từ không gian tên gốc (trong trường hợp này là không gian tên chung), đó là lý do tại sao chúng ta có thể gọi doSomething từ main mà không cần bất kỳ định nghĩa nào.
Điều này có thể làm cho không gian tên không được đặt tên dường như vô dụng. Nhưng tác động khác của không gian tên chưa được đặt tên là tất cả các số nhận dạng bên trong không gian tên không được đặt tên được coi như thể chúng có liên kết nội bộ, có nghĩa là nội dung của không gian tên chưa được đặt tên không thể được nhìn thấy bên ngoài tệp trong đó không gian tên chưa được xác định.
Đối với các hàm, điều này thực sự giống như việc xác định tất cả các hàm trong không gian tên chưa được đặt tên như các hàm tĩnh. Chương trình sau đây hoàn toàn giống với chương trình ở trên:
#include <iostream>
static void doSomething() // can only be accessed in this file
{
std::cout << "v1\n";
}
int main()
{
doSomething(); // we can call doSomething() without a namespace prefix
return 0;
}
Không gian tên chưa được đặt tên thường được sử dụng khi bạn có nhiều nội dung mà bạn muốn đảm bảo giữ nguyên cục bộ cho một tệp nhất định, vì việc tập hợp nội dung đó trong một không gian tên chưa được đặt tên sẽ dễ dàng hơn so với đánh dấu riêng lẻ tất cả các khai báo là tĩnh. Không gian tên chưa được đặt tên cũng sẽ giữ các kiểu do người dùng xác định (điều gì đó chúng ta sẽ thảo luận trong bài học sau) biến cục bộ cho file, điều mà không có cơ chế tương đương thay thế nào thực hiện được.
2, Không gian tên nội tuyến
Bây giờ hãy xem xét chương trình sau:
#include <iostream>
void doSomething()
{
std::cout << "v1\n";
}
int main()
{
doSomething();
return 0;
}
Kết quả
v1
Khá đơn giản, phải không?
Nhưng giả sử bạn không hài lòng với doSomething và bạn muốn cải thiện nó theo một cách nào đó để thay đổi cách thức hoạt động của nó. Nhưng nếu bạn làm điều này, bạn có nguy cơ phá vỡ các chương trình hiện có bằng phiên bản cũ hơn. Làm thế nào bạn có thể xoay xở được chuyện này?
Có một cách là tạo một phiên bản mới của hàm với một tên khác. Nhưng qua nhiều lần thay đổi, bạn có thể kết thúc với một tập hợp các hàm gần như giống hệt nhau (doSomething, doSomething_v2, doSomething_v3, v.v.).
Một giải pháp thay thế là sử dụng không gian tên nội tuyến. Không gian tên nội tuyến là không gian tên thường được sử dụng để phiên bản nội dung. Giống như một không gian tên chưa được đặt tên, bất cứ thứ gì được khai báo bên trong một không gian tên nội tuyến đều được coi là một phần của không gian tên góc. Tuy nhiên, không gian tên nội tuyến không cung cấp cho mọi thứ liên kết nội bộ.
Để xác định không gian tên nội tuyến, chúng ta sử dụng từ khóa nội tuyến:
#include <iostream>
inline namespace v1 // declare an inline namespace named v1
{
void doSomething()
{
std::cout << "v1\n";
}
}
namespace v2 // declare a normal namespace named v2
{
void doSomething()
{
std::cout << "v2\n";
}
}
int main()
{
v1::doSomething(); // calls the v1 version of doSomething()
v2::doSomething(); // calls the v2 version of doSomething()
doSomething(); // calls the inline version of doSomething() (which is v1)
return 0;
}
Kết quả
v1
v2
v1
Trong ví dụ trên, người gọi doSomething sẽ nhận được v1 (phiên bản nội tuyến) của doSomething. Người gọi muốn sử dụng phiên bản mới hơn có thể gọi rõ ràng v2 :: dosomething (). Điều này bảo toàn hàm của các chương trình hiện có trong khi cho phép các chương trình mới hơn tận dụng các biến thể mới hơn / tốt hơn.
Ngoài ra, nếu bạn muốn đẩy phiên bản mới hơn:
namespace v1 // declare a normal namespace named v1
{
void doSomething()
{
std::cout << "v1\n";
}
}
inline namespace v2 // declare an inline namespace named v2
{
void doSomething()
{
std::cout << "v2\n";
}
}
int main()
{
v1::doSomething(); // calls the v1 version of doSomething()
v2::doSomething(); // calls the v2 version of doSomething()
doSomething(); // calls the inline version of doSomething() (which is v2)
return 0;
}
Kết quả:
v1
v2
v2
Trong ví dụ này, tất cả những người gọi đến doSomething sẽ nhận được phiên bản v2 theo mặc định (phiên bản mới hơn và tốt hơn). Người dùng vẫn muốn phiên bản cũ hơn của doSomething có thể gọi v1 :: doSomething () một cách rõ ràng để truy cập vào hành vi cũ. Điều này có nghĩa là các chương trình hiện có muốn có phiên bản v1 sẽ cần phải thay thế toàn cầu doSomething bằng v1 :: doSomething, nhưng điều này thường sẽ không có vấn đề nếu các hàm được đặt tên tốt.
Cài ứng dụng cafedev để dễ dàng cập nhật tin và học lập trình mọi lúc mọi nơi tại đây.
Nguồn và Tài liệu tiếng anh tham khảo:
Tài liệu từ cafedev:
- Full series tự học C++ từ cơ bản tới nâng cao tại đây nha.
- Ebook về C++ tại đây.
- Các series tự học lập trình MIỄN PHÍ khác
- Nơi liên hệ hợp tác hoặc quảng cáo cùng Cafedevn tại đây.
Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:
Chào thân ái và quyết thắng!