Thực tế là, trong C ++, điều này có phần phức tạp hơn tổ chức tiêu đề / nguồn C.
Trình biên dịch thấy gì?
Trình biên dịch thấy một tệp nguồn lớn (.cpp) với các tiêu đề của nó được đưa vào đúng cách. Tệp nguồn là đơn vị biên dịch sẽ được biên dịch thành tệp đối tượng.
Vì vậy, tại sao tiêu đề lại cần thiết?
Bởi vì một đơn vị biên dịch có thể cần thông tin về việc triển khai trong một đơn vị biên dịch khác. Vì vậy, người ta có thể viết ví dụ về việc thực hiện một hàm trong một nguồn và viết phần khai báo của hàm này trong một nguồn khác cần sử dụng nó.
Trong trường hợp này, có hai bản sao của cùng một thông tin. Cái nào ác ...
Giải pháp là chia sẻ một số chi tiết. Trong khi việc triển khai vẫn ở trong Nguồn, việc khai báo các ký hiệu được chia sẻ, như hàm hoặc định nghĩa cấu trúc, lớp, enum, v.v., có thể cần được chia sẻ.
Tiêu đề được sử dụng để đặt những chi tiết được chia sẻ.
Di chuyển đến tiêu đề các khai báo về những gì cần được chia sẻ giữa nhiều nguồn
Chỉ có bấy nhiêu thôi?
Trong C ++, có một số thứ khác có thể được đưa vào tiêu đề vì chúng cũng cần được chia sẻ:
- mã nội tuyến
- mẫu
- hằng số (thường là những hằng số bạn muốn sử dụng bên trong công tắc ...)
Di chuyển đến tiêu đề MỌI THỨ những gì cần được chia sẻ, bao gồm cả các triển khai được chia sẻ
Sau đó, nó có nghĩa là có thể có các nguồn bên trong các tiêu đề?
Đúng. Trên thực tế, có rất nhiều thứ khác nhau có thể nằm trong một "tiêu đề" (tức là được chia sẻ giữa các nguồn).
- Chuyển tiếp khai báo
- khai báo / định nghĩa hàm / cấu trúc / lớp / mẫu
- triển khai mã nội tuyến và mã mẫu
Nó trở nên phức tạp và trong một số trường hợp (phụ thuộc vòng tròn giữa các ký hiệu), không thể giữ nó trong một tiêu đề.
Tiêu đề có thể được chia thành ba phần
Điều này có nghĩa là, trong trường hợp cực đoan, bạn có thể có:
- một tiêu đề khai báo chuyển tiếp
- một tiêu đề khai báo / định nghĩa
- một tiêu đề triển khai
- một nguồn thực hiện
Hãy tưởng tượng chúng ta có một MyObject được tạo mẫu. Chúng ta có thể có:
// - - - - MyObject_forward.hpp - - - -
// This header is included by the code which need to know MyObject
// does exist, but nothing more.
template<typename T>
class MyObject ;
.
// - - - - MyObject_declaration.hpp - - - -
// This header is included by the code which need to know how
// MyObject is defined, but nothing more.
#include <MyObject_forward.hpp>
template<typename T>
class MyObject
{
public :
MyObject() ;
// Etc.
} ;
void doSomething() ;
.
// - - - - MyObject_implementation.hpp - - - -
// This header is included by the code which need to see
// the implementation of the methods/functions of MyObject,
// but nothing more.
#include <MyObject_declaration.hpp>
template<typename T>
MyObject<T>::MyObject()
{
doSomething() ;
}
// etc.
.
// - - - - MyObject_source.cpp - - - -
// This source will have implementation that does not need to
// be shared, which, for templated code, usually means nothing...
#include <MyObject_implementation.hpp>
void doSomething()
{
// etc.
} ;
// etc.
Chà!
Trong "cuộc sống thực", nó thường ít phức tạp hơn. Hầu hết mã sẽ chỉ có tiêu đề / tổ chức nguồn đơn giản, với một số mã nội tuyến trong nguồn.
Nhưng trong các trường hợp khác (các đối tượng được tạo khuôn mẫu biết nhau), tôi phải có các tiêu đề khai báo và triển khai riêng cho từng đối tượng, với một nguồn trống bao gồm các tiêu đề đó chỉ để giúp tôi xem một số lỗi biên dịch.
Một lý do khác để chia nhỏ các tiêu đề thành các tiêu đề riêng biệt có thể là để tăng tốc quá trình biên dịch, hạn chế số lượng ký hiệu được phân tích cú pháp ở mức nghiêm ngặt cần thiết và tránh biên dịch lại không cần thiết đối với một nguồn chỉ quan tâm đến khai báo chuyển tiếp khi việc triển khai phương thức nội tuyến thay đổi.
Phần kết luận
Bạn nên làm cho tổ chức mã của mình đơn giản nhất có thể và theo mô-đun càng tốt. Đặt càng nhiều càng tốt vào tệp nguồn. Chỉ hiển thị trong tiêu đề những gì cần được chia sẻ.
Nhưng một ngày bạn sẽ có sự phụ thuộc vòng tròn giữa các đối tượng được tạo mẫu, đừng ngạc nhiên nếu tổ chức mã của bạn trở nên "thú vị" hơn khi tổ chức tiêu đề / nguồn đơn giản ...
^ _ ^