[Khóa học C++] Bài 15 - Header files

Share:

Headers, and their purpose

Trong bài 13, bạn đã biết là trong các chương trình lớn, chúng ta sẽ chia nhỏ source code ra thành nhiều file, nếu bạn để ý một chút, bạn có thể thấy, với mỗi function bạn muốn sử dụng trong một file khác, bạn phải có một forward declaration. Vậy khi chương trình của bạn càng lớn, bạn sẽ có một đống forward declaration. Ý tưởng ở đây là bạn có thể nào đặt tất cả forward declaration vào một nơi nào đó?

Trong chương trình C++, không phải chỉ có file code (.cpp) là file phổ biến, một loại file phổ biến khác mà luôn luôn đi chung với file .cpp, chính là header file, hoặc bạn có thể gọi là include file. Code file có phần mở là .cpp, còn header file có phần mở rộng là .h. Tuy nhiên, trong một số trường hợp, bạn có thể thấy phần mở rộng của header file có thể là .hpp hoặc không có phần mở rộng.
Và mục đích của header file là lưu trữ các declaration cho những file khác sử dụng.

Using standard library header files

Chúng ta xem chương trình sau

Chương trình này quá quen thuộc với bạn, chương trình sẽ in ra Hello, world! trên màn hình console. Bạn có để ý rằng hàm cout không hề có một forward declaration nào nhưng vẫn sử dụng được (theo bài 12). Câu trả lời chính là, forward declaration của hàm cout đã được tạo trong header file tên là iostream.
Khi bạn dùng câu lệnh #include <iostream>, tất cả nội dung trong file iostream sẽ được copy vào file code .cpp ngay tại vị trí nó include iostream.

Bạn hãy luôn nhớ rằng, header file chỉ chứa đụng các declaration, nó không chứa các implementation (ví dụ body của hàm là một implementation).

Khi bạn define một hàm, thì hàm này phải có một forward declaration và definition (hay body của hàm), bạn đã biết forward declaration của cout ở trong file iostream, vậy definition của cout ở đâu?
Câu trả lời là, nó ở trong thư viện runtime support của C++ (C++ runtime support library). Bạn hãy xem hình bên dưới.

Writing your own header files

Bạn hãy quay lại ví dụ trong bài 13, chúng ta có 2 file add.cpp và main.cpp như bên dưới.
add.cpp
main.cpp
Với những hiểu biết từ đầu series tới giờ,bạn có thể tự viết cho mình header file để hoàn thiện ví dụ trên.
Note: Header file giúp source code của bạn dễ bảo trì, update, và tối ưu hóa chương trình của bạn. Header file có 2 phần: header guard giúp bạn tránh việc include 2 lần trong 1 file (bạn sẽ học trong bài preprocessor). Và nội dung header file chứa tất cả những declarations.
Quay lại ví dụ, bây giờ chúng ta sẽ thiết kế header file cho ví dụ trên với tên add.h.

Chúng ta sẽ include add.h trong file main.cpp.


Khi compiler biên dịch dòng #include "add.h", nó sẽ copy tất cả nội dung của file add.h vào vị trí được include này. Bởi vì add.h chưa prototype của hàm add(), và prototype này chính sẽ trở thành forward declaration của hàm add().
Bạn hãy xem hình dưới để hiểu rõ hơn về cách làm việc của trình biên dịch.

Angled brackets vs quotes

Bạn có thể thắc mắc rằng, chúng tôi đã sử dụng dấu ngoặc nhọn <> (angled brackets) và dấu nháy kép "" (double quotes).
Câu trả lời là, chúng ta dùng dấu ngoặc nhọn khi chúng ta include các header file hệ thống (như stdio.h, iostream, ...), và dấu nháy kép thường dùng đối với các header file do người lập trình viên tự thiết kế.

Why doesn't iostream have a .h extension?

Bạn có tự hỏi rằng tại sau file iostream lại không có đuôi .h.
Câu trả lời là, iostream.h là một header file hoàn toàn khác với iostream.

Khi C++ mới được tạo ra, tất cả các header file hệ thống (standard runtime library) đều có đuôi .h. Và khi người ta quyết định di chuyển tất cả các function trong standard library và std namespace (xem lại bài namespace), thì tất cả các chương trình C++ cũ trước đó không thể hoạt động được nữa.

Vì vậy, để duy trì sự hoạt động của các chương trình C++ đã viết, các header file giống với header file cũ nhưng không có đuôi .h được ra đời. Cho nên ngày nay chúng ta có cả iostream.h và iostream.
Note: Chúng ta không nên dùng các file header cũ với đuôi .h nếu phiên bản không có đuôi .h tồn tại.
Header file best practices

Sau đây là một số đề nghị khi sử dụng header file:
  • Luôn luôn sử dụng header guards.
  • Không define các biến trong header file (ngoại trừ constants -  hằng số)
  • Không define body function trong header file.
  • Mỗi header file nên có một chức năng riệng biệt, ví dụ A.h thì define tất cả các prototype cho A.cpp, tương tự B.h cho B.cpp
  • Sử dụng header file có tên giống với tên của code file, ví dụ lenhatthanh.h đi cùng với lenhatthanh.cpp
  • Không #include .cpp file.
  • Tối ưu hóa cho header file, include header file chỉ khi cần thiết.



Không có nhận xét nào