Php sử dụng không gian tên chung
Đây là một trong những câu hỏi thường gặp trong buổi phỏng vấn. Hầu hết các ứng viên đều đạt thứ nhất, và một số thứ hai, thứ ba và có thể là thứ 4 nữa. Nhưng hiếm khi họ giải quyết vấn đề thứ 5
Đối tượng tĩnh là đối tượng tồn tại từ khi nó được tạo cho đến khi kết thúc chương trình. Vì vậy, các đối tượng ngăn xếp và đống được loại trừ. Nhưng các đối tượng toàn cầu, các đối tượng ở phạm vi không gian tên, các đối tượng được khai báo tĩnh bên trong các lớp/hàm và các đối tượng được khai báo ở phạm vi tệp được bao gồm trong các đối tượng tĩnh. Các đối tượng tĩnh bị hủy khi chương trình ngừng chạy Các biến được xác định bên ngoài hàm hoặc bằng cách sử dụng từ khóa tĩnh có thời lượng lưu trữ tĩnh. Chúng tồn tại trong toàn bộ thời gian chạy của một chương trình Các biến này có thể được phân loại thành ba nhóm về mặt liên kết
Vì các biến tĩnh giữ nguyên trong suốt vòng đời của chương trình nên chúng dễ dàng xử lý đối với hệ thống bộ nhớ và chúng được phân bổ trong một khối bộ nhớ cố định Dưới đây là một ví dụ về các biến tĩnh với thời lượng khác nhau int a= 1; static int b = 2; int main() {} void f() { static int c = 3; int d = 4; } Tất cả các biến tĩnh tồn tại cho đến khi chương trình kết thúc. Biến d có phạm vi cục bộ và không có liên kết - nó không được sử dụng bên ngoài f(). Nhưng c vẫn còn trong bộ nhớ ngay cả khi chức năng f() không được thực thi. Bằng cách nói rằng c là tĩnh, chúng ta đang nói rằng chúng ta muốn phân bổ nó một lần và chỉ một lần, tại một thời điểm nào đó trước khi hàm f() được gọi lần đầu tiên và chúng ta không muốn phân bổ nó miễn là chương trình của chúng ta Cả a và b đều có thể được truy cập từ điểm khai báo cho đến khi kết thúc tệp. Nhưng a có thể được sử dụng trong các tệp khác vì nó có liên kết bên ngoài Tất cả các biến thời lượng tĩnh có các đặc điểm khởi tạo sau
int x; // x set to 0 int y = 50; // 50 is literal constant int z = sizeof(int); // sizeof ok int zz = 10 * x; // not allowed, x is not constant int main() {...} Trong C ++ đã mang lại một chút thay đổi cho các lớp lưu trữ mặc định. Mặc dù biến toàn cục có liên kết bên ngoài theo mặc định, const toàn cầu có liên kết bên trong theo mặc định. Nói cách khác, C++ xử lý một định nghĩa const toàn cầu như thể tĩnh đã được sử dụng như trong đoạn mã sau const int a = 10; int main() { ... Vì vậy, "const int a = 10" trở thành "static const int a = 10". Tuy nhiên, nếu const toàn cầu có liên kết bên ngoài như các biến thông thường, khai báo const sẽ là lỗi vì chúng ta chỉ có thể định nghĩa một biến toàn cục trong một tệp. Nói cách khác, chỉ một tệp có thể chứa khai báo trước và các tệp khác phải cung cấp khai báo tham chiếu bằng từ khóa bên ngoài. Lưu ý rằng chỉ những khai báo không có extern mới có thể khởi tạo giá trị Tuy nhiên, nếu chúng ta muốn tạo một hằng số có liên kết bên ngoài, chúng ta có thể sử dụng từ khóa bên ngoài để ghi đè lên liên kết bên trong mặc định extern const int a = 20; Ở đây, chúng ta nên sử dụng từ khóa extern để khai báo hằng trong tất cả các tệp có sử dụng hằng. Đó là sự khác biệt giữa các biến bên ngoài thông thường và hằng số. Đối với các biến ngoài thông thường, chúng tôi không sử dụng từ khóa extern khi xác định một biến, nhưng chúng tôi sử dụng extern trong các tệp khác sử dụng biến đó Một khai báo bên ngoài không xác định biến trừ khi nó cũng được khởi tạo trong cùng một câu lệnh extern int x; // declaration extern int x = 10; // definition Đối với chữ "C" bên ngoài, vui lòng truy cập Lưu trữ tĩnh và phân bổ động Bộ nhớ động được điều khiển bởi các toán tử mới và xóa, không phải bởi phạm vi và quy tắc liên kết. Vì vậy, bộ nhớ động có thể được cấp phát từ một chức năng và được giải phóng khỏi chức năng khác Mặc dù các lược đồ lưu trữ không áp dụng cho bộ nhớ động, nhưng áp dụng cho các biến con trỏ tĩnh và tự động được sử dụng để theo dõi bộ nhớ động Hãy nhìn vào dòng mã sau đây int *ptr = new int[10]; 40 byte bộ nhớ được phân bổ bởi bộ nhớ mới vẫn còn trong bộ nhớ cho đến khi xóa giải phóng nó. Nhưng con trỏ ptr chuyển từ sự tồn tại khi hàm chứa khai báo này kết thúc Nếu chúng ta muốn có sẵn 40 byte bộ nhớ được phân bổ từ một chức năng khác, chúng ta cần chuyển hoặc trả lại địa chỉ của nó cho chức năng đó Mặt khác, nếu chúng ta khai báo ptr với liên kết ngoài, con trỏ ptr sẽ khả dụng bằng cách sử dụng.extern int *ptr; Tuy nhiên, một câu lệnh sử dụng new to set ptr phải nằm trong một hàm vì các biến lưu trữ tĩnh chỉ có thể được khởi tạo với các biểu thức hằng số như trong ví dụ sau int *ptr; // initialization with non-const not allowed here // int *ptr = new int[10]; int main() { ptr = new int[10]; ... Xem Phân bổ bộ nhớ Các thành viên tĩnh tồn tại với tư cách là thành viên của lớp chứ không phải là một thể hiện trong mỗi đối tượng của lớp. Vì vậy, từ khóa này không có sẵn trong hàm thành viên tĩnh. Các chức năng như vậy chỉ có thể truy cập các thành viên dữ liệu tĩnh. Có một thể hiện duy nhất của mỗi thành viên dữ liệu tĩnh cho toàn bộ lớp, cần được khởi tạo, thường là trong tệp nguồn thực hiện các hàm thành viên của lớp. Bởi vì thành viên được khởi tạo bên ngoài định nghĩa lớp, chúng ta phải sử dụng tên đủ điều kiện khi chúng ta khởi tạo nó ________số 8Đây là ví dụ thực tế, Xe hơi. h class Car { private: static int id; public: Car(); ... }; Hồ sơ thực hiện, Ô tô. cpp int x; // x set to 0 int y = 50; // 50 is literal constant int z = sizeof(int); // sizeof ok int zz = 10 * x; // not allowed, x is not constant int main() {...}0 Mã khởi tạo thành viên id tĩnh thành 100. Một lần nữa lưu ý rằng chúng ta không thể khởi tạo biến thành viên tĩnh bên trong khai báo lớp. Đó là bởi vì phần khai báo là một mô tả về cách cấp phát bộ nhớ, nhưng nó không cấp phát bộ nhớ. Chúng tôi phân bổ và khởi tạo bộ nhớ bằng cách tạo một đối tượng sử dụng định dạng đó Trong trường hợp thành viên lớp tĩnh, chúng tôi khởi tạo thành viên tĩnh một cách độc lập, với một câu lệnh riêng bên ngoài khai báo lớp. Đó là bởi vì thành viên lớp tĩnh được lưu trữ riêng chứ không phải là một phần của đối tượng Ngoại lệ đối với việc khởi tạo thành viên dữ liệu tĩnh bên trong khai báo lớp là nếu thành viên dữ liệu tĩnh là hằng số của kiểu tích phân hoặc kiểu liệt kê int x; // x set to 0 int y = 50; // 50 is literal constant int z = sizeof(int); // sizeof ok int zz = 10 * x; // not allowed, x is not constant int main() {...}1 Ví dụ sau đây cho thấy quyền truy cập bất hợp pháp vào thành viên không tĩnh từ một hàm tĩnh int x; // x set to 0 int y = 50; // 50 is literal constant int z = sizeof(int); // sizeof ok int zz = 10 * x; // not allowed, x is not constant int main() {...}2 Trong hàm f(), x=z là một lỗi vì f(), một hàm tĩnh, đang cố truy cập thành viên không tĩnh x Vì vậy, sửa chữa nên như thế này int x; // x set to 0 int y = 50; // 50 is literal constant int z = sizeof(int); // sizeof ok int zz = 10 * x; // not allowed, x is not constant int main() {...}3 Không thể sử dụng các thành viên không tĩnh làm đối số mặc định Đoạn mã sau cho thấy không thể sử dụng thành viên không tĩnh làm đối số mặc định int x; // x set to 0 int y = 50; // 50 is literal constant int z = sizeof(int); // sizeof ok int zz = 10 * x; // not allowed, x is not constant int main() {...}4 Dưới đây là một số đặc điểm của các hàm thành viên tĩnh
Tĩnh - Mẫu Singleton Mẫu thiết kế Singleton là một ví dụ điển hình về hàm thành viên tĩnh và biến thành viên tĩnh. Trong mẫu này, chúng tôi đặt hàm tạo trong phần riêng tư không phải trong phần chung của một lớp. Vì vậy, chúng ta không thể truy cập hàm tạo để tạo một thể hiện của lớp. Thay vào đó, chúng tôi đặt một hàm công khai là hàm tĩnh. getInstance() sẽ chỉ tạo một phiên bản một lần. Lưu ý rằng nếu phương thức này không phải là tĩnh, thì không có cách nào để gọi phương thức getInstance() mặc dù đó là phương thức công khai. Đó là bởi vì chúng tôi không có bất kỳ phiên bản Singleton nào int x; // x set to 0 int y = 50; // 50 is literal constant int z = sizeof(int); // sizeof ok int zz = 10 * x; // not allowed, x is not constant int main() {...}5 Đầu ra là int x; // x set to 0 int y = 50; // 50 is literal constant int z = sizeof(int); // sizeof ok int zz = 10 * x; // not allowed, x is not constant int main() {...}6 Liên kết bên ngoài và từ khóa tĩnh Liên kết bên ngoài có nghĩa là một biểu tượng trong một đơn vị dịch thuật có thể được truy cập từ các đơn vị dịch thuật khác. Trừ khi chúng ta thực hiện các bước đặc biệt, các hàm và biến toàn cục trong. cpp sẽ có liên kết bên ngoài int x; // x set to 0 int y = 50; // 50 is literal constant int z = sizeof(int); // sizeof ok int zz = 10 * x; // not allowed, x is not constant int main() {...}7 Đây là mã có thể truy cập My_CONSTANT, My_NAME và My_Function() mà không cần sử dụng giao diện công khai, do đó phá vỡ tính đóng gói int x; // x set to 0 int y = 50; // 50 is literal constant int z = sizeof(int); // sizeof ok int zz = 10 * x; // not allowed, x is not constant int main() {...}8 Một cách để tránh vấn đề liên kết này là sử dụng từ khóa tĩnh int x; // x set to 0 int y = 50; // 50 is literal constant int z = sizeof(int); // sizeof ok int zz = 10 * x; // not allowed, x is not constant int main() {...}9 Mặc dù chúng ta có thể tránh được vấn đề liên kết bên ngoài bằng cách sử dụng từ khóa tĩnh nhưng nó vẫn có vấn đề gây ô nhiễm không gian tên toàn cầu. Vì vậy, giải pháp cho người đánh bóng là sử dụng không gian tên ẩn danh như hình bên dưới |