Xem thêm

Con trỏ void (Con trỏ không rõ kiểu)

Huy Erick
Trong bài học trước, chúng ta đã được giới thiệu về Biến tham chiếu trong ngôn ngữ lập trình C++. Hôm nay, chúng ta sẽ tiếp tục tìm hiểu về con trỏ trong C++, đặc...

Trong bài học trước, chúng ta đã được giới thiệu về Biến tham chiếu trong ngôn ngữ lập trình C++. Hôm nay, chúng ta sẽ tiếp tục tìm hiểu về con trỏ trong C++, đặc biệt là con trỏ void.

Để hiểu rõ bài này, bạn nên có kiến thức cơ bản về con trỏ trong C++. Trong bài viết này, chúng ta sẽ cùng tìm hiểu các vấn đề sau:

Con trỏ void (Con trỏ không rõ kiểu)

Bạn cần nhớ rằng một con trỏ truyền tải hai thông tin: kiểu dữ liệu trỏ đến và địa chỉ của vùng nhớ mà nó trỏ tới. Kiểu dữ liệu trỏ đến quy định cách truy xuất dữ liệu, trong khi địa chỉ của vùng nhớ quy định nơi bạn có thể truy xuất dữ liệu.

Một con trỏ void là một con trỏ không chỉ định thông tin kiểu dữ liệu. Nó cho bạn biết dữ liệu được lưu ở đâu, nhưng không cho bạn biết cách truy xuất dữ liệu đó. Con trỏ void còn được gọi là con trỏ tổng quát, là một kiểu con trỏ đặc biệt có thể trỏ đến các đối tượng của bất kỳ kiểu dữ liệu nào.

Để khai báo một con trỏ void, bạn sử dụng từ khóa void làm kiểu con trỏ:

void *ptr; // ptr là con trỏ void

Con trỏ void có thể trỏ đến các đối tượng của bất kỳ kiểu dữ liệu nào:

int n;
float f;
double d;
void *ptr;
ptr = &n; // ok
ptr = &f; // ok
ptr = &d; // ok

Tuy nhiên, con trỏ void không xác định được kiểu dữ liệu của vùng nhớ mà nó trỏ tới, chúng ta không thể truy xuất trực tiếp nội dung thông qua toán tử dereference (*). Vì vậy, con trỏ kiểu void cần phải được ép kiểu một cách rõ ràng sang con trỏ có kiểu dữ liệu khác trước khi sử dụng toán tử dereference (*).

int value = 10;
void *voidPtr = &value; 
int *intPtr = static_cast(voidPtr); 

cout << *intPtr << endl;

Trong đoạn code trên, voidPtrintPtr đều trỏ vào địa chỉ của biến value, nhưng chúng ta chỉ có thể sử dụng toán tử dereference (*) lên con trỏ intPtr chứ không thể sử dụng cho con trỏ voidPtr, vì trình biên dịch không thể biết con trỏ voidPtr trỏ đến kiểu dữ liệu gì.

Ứng dụng con trỏ void

Một con trỏ void không xác định được kiểu dữ liệu của vùng nhớ mà nó trỏ tới. Vậy làm thế nào để chúng ta biết kiểu dữ liệu mà nó trỏ tới là gì (int, double, …).

Thông thường, để sử dụng được con trỏ void, bạn phải lấy thông tin về kiểu con trỏ theo cách khác (sử dụng thêm tham số hoặc biến cho biết kiểu con trỏ), sau đó ép kiểu con trỏ đó đến một kiểu cụ thể (int, double, …) và sau đó sử dụng nó như bình thường.

Ví dụ:

#include 
using namespace std;

enum Type { INT, DOUBLE };

void printValueOfPointer(void *ptr, Type type) {
    switch (type) {
        case INT:
            cout << *(static_cast(ptr)) << '\n';
            break;
        case DOUBLE:
            cout << *(static_cast(ptr)) << '\n';
            break;
    }
}

int main() {
    int nValue = 10;
    double dValue = 6.9;

    printValueOfPointer(&nValue, INT);
    printValueOfPointer(&dValue, DOUBLE);

    return 0;
}

Con trỏ void (Void pointers)

Đoạn code trên hiển thị thông tin của con trỏ nValuedValue. Thông thường, chúng ta sẽ phải viết 2 hàm hiển thị cho 2 loại con trỏ này. Tuy nhiên, chúng ta có thể sử dụng tham số kiểu void*.

Khi vào hàm printValueOfPointer(), dựa vào biến type để ép từ kiểu void* về kiểu dữ liệu tương ứng. Điều này làm giảm thiểu việc viết nhiều function cùng chức năng nhưng khác kiểu dữ liệu đầu vào.

Hạn chế sử dụng con trỏ void

Thông thường, bạn nên tránh sử dụng con trỏ void trừ khi thật cần thiết. Vì chúng cho phép bạn tránh kiểm tra kiểu, điều này cho phép bạn vô tình làm những việc không có ý nghĩa, và trình biên dịch sẽ không thông báo lỗi.

Mặc dù hàm printValueOfPointer() là một cách ngắn gọn để xây dựng một hàm duy nhất xử lý nhiều kiểu dữ liệu. Tuy nhiên, C++ đã cung cấp một cách tốt hơn để làm điều tương tự thông qua nạp chồng hàm (function overloading), hoặc khuôn mẫu hàm (function template). Những khái niệm này sẽ được giới thiệu trong những bài học sau.

Kết luận

Qua bài học này, bạn đã nắm được con trỏ void (Con trỏ không rõ kiểu) trong C++. Hãy nhớ rằng bạn nên hạn chế lạm dụng nó, trừ khi không còn cách giải quyết nào khác.

Trong bài viết tiếp theo, mình sẽ giới thiệu cho các bạn khái niệm con trỏ trỏ đến con trỏ (Pointers to Pointers) trong C++.

Cảm ơn các bạn đã theo dõi bài viết. Hãy để lại bình luận hoặc góp ý của mình để phát triển bài viết tốt hơn. Đừng quên “Luyện tập - Thử thách - Không ngại khó”.

Thảo luận

Nếu bạn có bất kỳ khó khăn hay thắc mắc gì về khóa học, đừng ngần ngại đặt câu hỏi trong phần BÌNH LUẬN bên dưới hoặc trong mục HỎI & ĐÁP trên thư viện Howkteam.com để nhận được sự hỗ trợ từ cộng đồng.

1