2009-03-05 24 views
31

Các tiêu đề nào cần được khai báo trong tệp header/cpp? Rõ ràng những người được yêu cầu bởi các tiêu đề tiếp theo nên sớm hơn và lớp tiêu đề cụ thể nên trong phạm vi cpp không phạm vi tiêu đề, nhưng có một quy ước đặt hàng/thực hành tốt nhất?C++ Header order

Trả lời

59

Trong tệp tiêu đề, bạn phải bao gồm TẤT CẢ tiêu đề để làm cho tiêu đề có thể kết hợp được. Và đừng quên sử dụng các khai báo chuyển tiếp thay vì một số tiêu đề.

Trong một tập tin nguồn:

  • tập tin tương ứng với tiêu đề
  • tiêu đề dự án cần thiết
  • thư viện của bên thứ 3 Headers
  • thư viện chuẩn Headers
  • hệ thống tiêu đề

Trong đó đặt hàng bạn sẽ không bỏ lỡ bất kỳ của bạn r tập tin tiêu đề mà quên để bao gồm các thư viện của riêng mình.

+2

Tôi nghĩ rằng "các tiêu đề dự án cần thiết" nên tách biệt trên hai mục: - các tiêu đề dự án từ cùng một lib; - tiêu đề từ libs dự án khác (theo thứ tự mà hầu hết các tiêu đề libs dự án phổ biến theo dõi bên dưới một số tiêu đề libs dự án đặc biệt) – bayda

+2

Tôi thực sự thích đặt hàng của bạn. Cách này tiêu đề không dựa vào các tiêu đề khác để bao gồm dependecies của họ. – fmuecke

3

Tôi đã từng đặt hàng theo thứ tự bảng chữ cái (dễ tìm hơn)

+0

Đây là cách Epic cũng vậy, trong tài liệu kiểu Unreal Engine 4 của họ. –

0

Điều phụ thuộc phần lớn vào thứ bạn đặt vào tiêu đề của chúng tôi. Một thực tế là bạn có thể thực sự khét tiếng về điều này và giảm thiểu để giữ cho bạn bao gồm nghiêm ngặt nhưng cuối cùng bạn sẽ chạy vào một kịch bản mà bạn sẽ muốn sử dụng bảo vệ bao gồm.

#ifndef MY_HEADER_H 
#define MY_HEADER_H 
//... 
#endif 

Vấn đề không rõ ràng khi bắt đầu, nhưng vì sự phức tạp của phần mềm của bạn phát triển cũng như sự phụ thuộc của bạn. Bạn có thể làm tốt, và thông minh về nó, nhưng các dự án C++ lớn hơn thường được riddled với bao gồm. Bạn có thể thử, nhưng bạn chỉ có thể làm rất nhiều. Vì vậy, hãy siêng năng và suy nghĩ về sự bao gồm của bạn, CÓ! Nhưng bạn chắc chắn sẽ có những phụ thuộc theo chu kỳ tại một thời điểm nào đó và đó là lý do tại sao bạn cần phải bảo vệ.

+1

Điều này không giống như gọi '#pragma một lần'? – Konrad

+1

Có (nhiều hay ít) giống nhau, nhưng #pragma một lần không phải là tiêu chuẩn. –

+0

Đối với bản ghi #pragma một lần là một phần mở rộng của Microsoft. Nếu tôi đang làm việc trên một dự án đa nền tảng, tôi sử dụng nó cũng như bao gồm bảo vệ vì #pragma một khi thực sự ngăn phân tích cú pháp tệp. –

20

Thực hành tốt: mọi tệp .h phải có tệp .cpp bao gồm .h trước tiên trước bất kỳ thứ gì khác. Điều này chứng minh rằng bất kỳ tập tin .h có thể được đặt đầu tiên.

Ngay cả khi tiêu đề không yêu cầu triển khai, bạn tạo tệp .cpp chỉ bao gồm tệp .h và không có gì khác.

Điều này có nghĩa là bạn có thể trả lời câu hỏi của mình theo bất kỳ cách nào bạn muốn. Cho dù bạn có lời khuyên tuyệt vời nào, hãy thử cuốn sách này: Large-Scale C++ Software Design - thật đáng tiếc là nó quá đắt, nhưng nó thực sự là một hướng dẫn sinh tồn cho bố cục mã nguồn C++.

+0

Tôi làm điều này trong bài kiểm tra đơn vị của tôi để thay thế. – Ferruccio

+4

Dễ dàng hơn để tự động kiểm tra: chỉ cần biên dịch (-c) mỗi tệp tiêu đề (có, g ++ -c blah.h) và đảm bảo nó biên dịch. Sau đó, bạn có thể ném các tệp đối tượng ra xa. –

+0

+1, có rất nhiều điều chưa được trả lời trong câu trả lời đó. Mẹo tuyệt vời! –

1

Đối với các tệp .cpp, bạn nên bao gồm tiêu đề của lớp hoặc bất kỳ thứ gì bạn đang triển khai trước tiên, vì vậy bạn nắm bắt trường hợp tiêu đề này thiếu một số bao gồm. Sau đó, hầu hết các nguyên tắc mã hóa có xu hướng bao gồm các tiêu đề hệ thống đầu tiên, các tiêu đề dự án thứ hai, ví dụ: Google C++ Style Guide.

0

Nếu tiêu đề cần tiêu đề khác thì tiêu đề chỉ bao gồm tiêu đề đó trong tiêu đề đó.

Cố gắng cấu trúc mã của bạn để bạn chuyển con trỏ hoặc tham chiếu và chuyển tiếp đến nơi bạn có thể.

Trong khi triển khai, tiêu đề xác định đầu tiên sẽ được liệt kê (ngoại trừ trong Visual Studio nếu bạn đang sử dụng pch thì stdafx sẽ đi trước).

Tôi thường liệt kê chúng khi cần.

6

Trong tệp tiêu đề, tôi có xu hướng đặt tiêu đề chuẩn đầu tiên, sau đó là tiêu đề của riêng tôi (cả hai danh sách được sắp xếp theo thứ tự bảng chữ cái). Trong các tệp triển khai, tôi đặt đầu tiên tương ứng với tiêu đề (nếu có), sau đó là tiêu đề chuẩn và các tiêu đề phụ thuộc khác.

Đặt hàng có tầm quan trọng rất ít, ngoại trừ nếu bạn sử dụng tuyệt vời macro và #define; trong trường hợp đó, bạn phải kiểm tra xem macro bạn đã xác định không thay thế một macro được bao gồm trước đây (ngoại trừ nếu đó là những gì bạn muốn, tất nhiên).

Về tuyên bố này

những người được yêu cầu của tiêu đề tiếp theo nên sớm

Một tiêu đề không nên dựa vào tiêu đề khác được bao gồm trước khi nó! Nếu nó đòi hỏi tiêu đề, nó chỉ bao gồm chúng. bảo vệ phần đầu sẽ ngăn chặn nhiều bao gồm:

#ifndef FOO_HEADER_H 
#define FOO_HEADER_H 
... 
#endif 

EDIT

Kể từ khi tôi đã viết câu trả lời này, tôi đã thay đổi cách của tôi ra lệnh bao gồm các chỉ thị trong mã của tôi. Bây giờ, tôi luôn cố gắng đặt tiêu đề theo thứ tự tiêu chuẩn hóa ngày càng tăng, vì vậy các tiêu đề của dự án của tôi xuất hiện đầu tiên, tiếp theo là tiêu đề thư viện của bên thứ ba, tiếp theo là tiêu đề chuẩn.

Ví dụ, nếu một trong các tập tin của tôi sử dụng một thư viện tôi đã viết, Qt, Tăng và các thư viện chuẩn, tôi sẽ đặt hàng bao gồm như sau:

//foo.cpp 
#include "foo.hpp" 

#include <my_library.hpp> 
// other headers related to my_library 

#include <QtCore/qalgorithms.h> 
// other Qt headers 

#include <boost/format.hpp> // Boost is arguably more standard than Qt 
// other boost headers 

#include <algorithms> 
// other standard algorithms 

Lý do tại sao tôi làm điều đó là để phát hiện thiếu phụ thuộc trong các tiêu đề của chính tôi: giả sử ví dụ: my_library.hpp sử dụng std::copy, nhưng không bao gồm <algorithm>. Nếu tôi bao gồm sau <algorithm> trong foo.cpp, phụ thuộc bị thiếu này sẽ không được chú ý. Ngược lại, với thứ tự tôi vừa trình bày, trình biên dịch sẽ phàn nàn rằng std::copy chưa được khai báo, cho phép tôi chỉnh sửa my_library.hpp.

Trong mỗi nhóm "thư viện", tôi cố gắng giữ các chỉ thị bao gồm theo thứ tự bảng chữ cái, để tìm chúng dễ dàng hơn.

Trên sidenote, thực hành tốt cũng là giới hạn tối đa sự phụ thuộc giữa các tệp tiêu đề. Tệp phải bao gồm các tiêu đề nhỏ nhất có thể, đặc biệt là tệp tiêu đề. Thật vậy, bạn càng thêm nhiều tiêu đề, mã càng cần được biên dịch lại khi có thay đổi. Cách tốt nhất để hạn chế những phụ thuộc này là sử dụng khai báo chuyển tiếp, thường rất đủ trong các tệp tiêu đề (xem When can I use a forward declaration?).

+0

+1 cho bộ bao gồm/tiêu đề bảo vệ. – polarise

-1

Tôi đã tìm thấy quy ước sau hữu ích nhất:

mô-đun.cpp:

// this is the header used to trigger inclusion of precompiled headers 
#include <precompiled.h> 
// this ensures that anything that includes "module.h" works 
#include "module.h" 
// other headers, usually system headers, the project 

Điều quan trọng là đặt tiêu đề của mô-đun làm tiêu đề đầu tiên không được biên dịch trước. Điều này đảm bảo "module.h" không có phụ thuộc bất ngờ.

Nếu bạn đang làm việc trên một dự án lớn với thời gian truy cập đĩa chậm, tôi đã nhìn thấy phong cách này được sử dụng để giảm build lần:

module.cpp:

// this is the header used to trigger inclusion of precompiled headers 
#include <precompiled.h> 
// this ensures that anything that includes "module.h" works 
#include "module.h" 
// other headers, usually system headers, the project 
#if !defined _OTHER_MODULE_GUARD_ 
#include "other_module.h" 
#endif 

#if !defined _ANOTHER_MODULE_GUARD_ 
#include "another_module.h" 
#endif 

Đó là một chút dài dòng nhưng không lưu trên đĩa tìm kiếm vì tiêu đề sẽ không được tìm kiếm/mở nếu nó đã được bao gồm. Nếu không có kiểm tra bảo vệ, trình biên dịch sẽ tìm kiếm và mở tệp tiêu đề, phân tích cú pháp toàn bộ tệp để kết thúc tệp #ifdef ing toàn bộ tệp.

2

Cách "hiển thị" không rõ ràng, nhưng "cái" là gì. Mục tiêu của bạn là đảm bảo rằng thứ tự mà bạn bao gồm các tệp tiêu đề không bao giờ là vấn đề (và tôi có nghĩa là "KHÔNG BAO GIỜ!").

Một trợ giúp tốt là kiểm tra xem tệp tiêu đề có biên dịch hay không khi tạo tệp cpp (một tệp cho mỗi tệp tiêu đề) chỉ bao gồm một trong số chúng.

5

Google C++ Style Guide, Names and Order of Includes:

Trong dir/foo.cc, mà mục đích chính là để thực hiện hoặc kiểm tra những thứ trong dir2/foo2.h, đặt hàng bao gồm như sau:

  • dir2/foo2.h (vị trí ưa thích - xem chi tiết bên dưới).
  • tệp hệ thống C.
  • Tệp hệ thống C++.
  • Các tệp .h của thư viện khác.
  • Tệp .h của dự án của bạn.
+5

yeah nhưng ggl phong cách hướng dẫn có một số điều khó chịu trong nó :) –