Lớp lưu trữ trong C++
Xin chào các bạn đang học lập trình! Hôm nay, chúng ta sẽ bắt đầu một hành trình thú vị qua thế giới của các lớp lưu trữ trong C++. Đừng lo lắng nếu bạn mới bắt đầu học lập trình; tôi sẽ là người hướng dẫn thân thiện của bạn, giải thích mọi thứ từng bước. Hãy cùng nhau khám phá nhé!
Lớp lưu trữ là gì?
Trước khi chúng ta đi vào chi tiết, hãy hiểu lớp lưu trữ là gì. Trong C++, các lớp lưu trữ xác định phạm vi (tính khả见) và thời gian tồn tại của các biến và hàm trong chương trình. Chúng cho biết cách biên dịch器 lưu trữ biến, liệu nó có thể truy cập từ các tệp khác hay không, và nó nên tồn tại trong bộ nhớ bao lâu.
Bây giờ, hãy cùng tìm hiểu chi tiết từng lớp lưu trữ.
Lớp lưu trữ auto
Từ khóa auto
trong C++ đã thay đổi ý nghĩa của nó theo từng phiên bản. Trong C++ hiện đại (C++11 và sau), nó được sử dụng cho suy luận kiểu. Tuy nhiên, trong các phiên bản cũ, nó là một chỉ định lớp lưu trữ.
Sử dụng cũ (trước C++11):
int main() {
auto int x = 5; // Tương đương với: int x = 5;
return 0;
}
Trong cách sử dụng cũ này, auto
khẳng định một biến có thời gian tồn tại tự động. Tuy nhiên, đây là mặc định cho các biến cục bộ, vì vậy nó hiếm khi được sử dụng.
Sử dụng hiện đại (C++11 và sau):
int main() {
auto x = 5; // x suy luận là int
auto y = 3.14; // y suy luận là double
auto z = "Hello"; // z suy luận là const char*
return 0;
}
Trong C++ hiện đại, auto
cho phép biên dịch器 suy luận kiểu của biến dựa trên phần tử khởi tạo. Nó đặc biệt hữu ích với các kiểu phức tạp hoặc khi kiểu có thể thay đổi trong tương lai.
Lớp lưu trữ register
Từ khóa register
là một gợi ý cho biên dịch器 rằng biến này sẽ được sử dụng nhiều và nên được giữ trong một thanh ghi CPU để truy cập nhanh hơn.
#include <iostream>
int main() {
register int counter = 0;
for(int i = 0; i < 1000000; i++) {
counter++;
}
std::cout << "Counter: " << counter << std::endl;
return 0;
}
Trong ví dụ này, chúng ta đang đề xuất với biên dịch器 rằng counter
nên được giữ trong một thanh ghi. Tuy nhiên, các biên dịch器 hiện đại thường rất thông minh và có thể tự động thực hiện các tối ưu hóa này, vì vậy register
hiếm khi được sử dụng trong thực tế.
Lớp lưu trữ static
Từ khóa static
có ý nghĩa khác nhau tùy thuộc vào nơi nó được sử dụng:
1. Biến cục bộ tĩnh
#include <iostream>
void countCalls() {
static int calls = 0;
calls++;
std::cout << "This function has been called " << calls << " times." << std::endl;
}
int main() {
for(int i = 0; i < 5; i++) {
countCalls();
}
return 0;
}
Trong ví dụ này, calls
chỉ được khởi tạo một lần và giữ giá trị của nó giữa các cuộc gọi hàm. Kết quả đầu ra sẽ là:
This function has been called 1 times.
This function has been called 2 times.
This function has been called 3 times.
This function has been called 4 times.
This function has been called 5 times.
2. Thành viên tĩnh của lớp
class MyClass {
public:
static int objectCount;
MyClass() {
objectCount++;
}
};
int MyClass::objectCount = 0;
int main() {
MyClass obj1;
MyClass obj2;
MyClass obj3;
std::cout << "Number of objects created: " << MyClass::objectCount << std::endl;
return 0;
}
Ở đây, objectCount
được chia sẻ giữa tất cả các thể hiện của MyClass
. Kết quả đầu ra sẽ là:
Number of objects created: 3
Lớp lưu trữ extern
Từ khóa extern
được sử dụng để khai báo một biến hoặc hàm toàn cục trong một tệp khác.
Tệp: globals.cpp
int globalVar = 10;
Tệp: main.cpp
#include <iostream>
extern int globalVar; // Khai báo của globalVar
int main() {
std::cout << "Global variable value: " << globalVar << std::endl;
return 0;
}
Trong ví dụ này, globalVar
được định nghĩa trong globals.cpp
và được khai báo là extern
trong main.cpp
. Điều này cho phép main.cpp
sử dụng biến được định nghĩa trong một tệp khác.
Lớp lưu trữ mutable
Từ khóa mutable
cho phép một thành viên của một đối tượng const có thể được sửa đổi.
class Person {
public:
Person(int age) : age(age), cacheValid(false) {}
int getAge() const {
if (!cacheValid) {
cachedAge = heavyComputation();
cacheValid = true;
}
return cachedAge;
}
private:
int age;
mutable int cachedAge;
mutable bool cacheValid;
int heavyComputation() const {
// Simulate a heavy computation
return age;
}
};
int main() {
const Person p(30);
std::cout << p.getAge() << std::endl; // Điều này được phép
return 0;
}
Trong ví dụ này, mặc dù p
là const, chúng ta vẫn có thể sửa đổi cachedAge
và cacheValid
vì chúng được đánh dấu là mutable
.
Tóm tắt
Hãy tóm tắt các lớp lưu trữ chúng ta đã học trong bảng handy:
Lớp lưu trữ | Mục đích |
---|---|
auto | Suy luận kiểu (C++ hiện đại) |
register | Gợi ý truy cập nhanh hơn (ít sử dụng) |
static | Giữ giá trị giữa các cuộc gọi hàm hoặc chia sẻ giữa các thể hiện của lớp |
extern | Khai báo biến hoặc hàm trong tệp khác |
mutable | Cho phép sửa đổi trong đối tượng const |
Nhớ rằng, việc hiểu các lớp lưu trữ là rất quan trọng để quản lý bộ nhớ hiệu quả và kiểm soát phạm vi của các biến. Khi bạn tiếp tục hành trình học C++, bạn sẽ thấy các khái niệm này trở nên quen thuộc. Chúc các bạn may mắn và vui vẻ lập trình!
Credits: Image by storyset