Chuyển tiếp khai báo vs bao gồm


17

Reduce the number of #include files in header files. It will reduce build times. Instead, put include files in source code files and use forward declarations in header files.

Tôi đọc nó ở đây. http://www.yolinux.com/TUTORIALS/LinuxTutorialC++CodingStyle.html .

Vì vậy, nó nói nếu một lớp (lớp A) trong tệp tiêu đề không cần sử dụng định nghĩa thực tế của một số lớp (lớp B). Tại thời điểm đó, chúng ta có thể sử dụng khai báo chuyển tiếp thay vì bao gồm tệp tiêu đề cụ thể (lớp B).

Câu hỏi: Nếu lớp (lớp A) trong tiêu đề nếu không sử dụng định nghĩa thực tế của một lớp cụ thể (lớp B), thì khai báo chuyển tiếp giúp giảm thời gian biên dịch như thế nào?

Câu trả lời:


11

Trình biên dịch không quan tâm nếu lớp A sử dụng lớp B. Nó chỉ biết rằng khi lớp A được biên dịch và nó không có khai báo trước của lớp B (khai báo chuyển tiếp hoặc nếu không), nó hoảng loạn và đánh dấu nó là một lỗi.

Điều quan trọng ở đây là trình biên dịch biết bạn đã không cố biên dịch chương trình sau khi con mèo của bạn đi trên bàn phím của bạn và tạo một số chữ cái ngẫu nhiên có thể hoặc không thể hiểu là một lớp.

Khi thấy bao gồm, để có thể sử dụng bất kỳ thông tin nào có trong đó, nó phải mở tệp và phân tích cú pháp (bất kể nó có thực sự cần phải làm như vậy hay không). Nếu tệp đó bao gồm các tệp khác, những tệp đó cũng phải được mở và phân tích cú pháp, v.v ... Nếu điều này có thể tránh được, nói chung nên sử dụng khai báo chuyển tiếp thay thế.

Chỉnh sửa : Ngoại lệ cho quy tắc này là các tiêu đề được biên dịch trước. Trong trường hợp này, tất cả các tiêu đề được biên dịch và lưu lại cho các phần tổng hợp trong tương lai. Nếu các tiêu đề không thay đổi, trình biên dịch có thể sử dụng thông minh các tiêu đề được biên dịch trước từ các phần tổng hợp trước đó và do đó cắt giảm thời gian biên dịch, nhưng nó chỉ hoạt động tốt nếu bạn thường không cần thay đổi các tiêu đề.


Cám ơn vì đã giải thích. Sau đó ok như ví dụ bạn nghĩ có ba tập tin tiêu đề vehicle.h, bus.h, toybus.h. vehicle.hbao gồm bởi bus.hbus.hbao gồm bởi toybus.h. Vì vậy, nếu tôi làm một số thay đổi trong bus.h. trình biên dịch mở và phân tích vehicle.hlại? nó biên dịch lại lần nữa?
Nayana Adassuriya

1
@NayanaAdassuriya Vâng, nó được bao gồm và phân tích cú pháp mỗi lần, đó cũng là lý do tại sao bạn nhìn thấy #pragma oncehoặc #ifndef __VEHICLE_H_nhập khai báo trong các tệp tiêu đề để ngăn các tệp đó được đưa vào nhiều lần (hoặc được sử dụng nhiều lần ít nhất trong trường hợp ifndef).
Neil

4

bởi vì sau đó A.hpp không cần #include B.hpp

vì vậy A.hpp trở thành

class B;//or however forward decl works for classes

class A
{
    B* bInstance_;
//...
}

do đó, khi A.hpp được bao gồm thì B.hpp không được bao gồm hoàn toàn và tất cả các tệp chỉ phụ thuộc vào A.hpp không cần phải biên dịch lại mỗi lần thay đổi b.hpp


nhưng trong tệp nguồn (A.cpp). cần bao gồm tệp tiêu đề thực tế (Bh). Vì vậy, mỗi khi nó cần biên dịch. Cuối cùng cả hai cách Bh cần biên dịch lại với những thay đổi. Có gì khác nhau không?
Nayana Adassuriya

@NayanaAdassuriya không vì A chỉ sử dụng một con trỏ tới B và thay đổi thành B sẽ không ảnh hưởng đến A.hpp (hoặc các tệp có chứa nó)
ratchet freak

@NayanaAdassuriya: Có, A.cpp sẽ phải biên dịch lại (nếu nó sử dụng định nghĩa B bên trong các phương thức của A, nhưng nó thường làm), nhưng C.cpp, sử dụng A, nhưng không trực tiếp B, sẽ không.
Jan Hudec

3

Hãy nhớ rằng, bộ tiền xử lý C / C ++ là một bước xử lý riêng biệt, hoàn toàn bằng văn bản. Lệnh #includenày kéo theo nội dung của tiêu đề đi kèm và trình biên dịch phải phân tích cú pháp. Hơn nữa, việc biên dịch từng cái .cpplà hoàn toàn riêng biệt, vì vậy thực tế là trình biên dịch chỉ phân tích cú pháp B.hkhi biên dịch B.cppkhông giúp ích gì cho nó khi nó cần lại khi biên dịch A.cpp. Và một lần nữa khi biên dịch C.cpp. Và D.cpp. Và như thế. Và mỗi tệp đó phải được biên dịch lại nếu có bất kỳ tệp nào trong đó bị thay đổi.

Vì vậy, nói rằng lớp Asử dụng lớp Bvà các lớp CDsử dụng lớp A, nhưng không cần phải thao tác B. Nếu lớp Acó thể được khai báo chỉ bằng khai báo chuyển tiếp B, hơn B.hđược biên dịch hai lần: khi biên dịch B.cppA.cpp(vì Bvẫn cần thiết trong Acác phương thức của).

Nhưng khi A.hbao gồm B.h, nó được biên dịch Bốn lần-khi biên soạn B.cpp, A.cpp, C.cppD.cppcàng về sau hai giờ gián tiếp bao gồm B.hquá.

Ngoài ra khi tiêu đề được bao gồm nhiều lần, bộ tiền xử lý vẫn phải đọc nó mỗi lần. Nó sẽ bỏ qua việc xử lý nội dung của nó vì các bảo vệ #ifdef, nhưng nó vẫn đọc nó và cần tìm kiếm phần cuối của bảo vệ, điều đó có nghĩa là nó phải phân tích tất cả các chỉ thị tiền xử lý bên trong.

(Như đã đề cập trong câu trả lời khác, các tiêu đề được biên dịch trước đang cố gắng khắc phục điều này, nhưng chúng là những con giun của riêng chúng; về cơ bản bạn có thể sử dụng chúng một cách hợp lý cho các tiêu đề hệ thống và chỉ khi bạn không sử dụng quá nhiều chúng, nhưng không phải cho tiêu đề trong dự án của bạn)


+1, tiêu đề bao gồm chỉ trở thành một vấn đề nghiêm trọng khi bạn có số lượng lớp khá lớn, không phải khi chỉ có hai lớp A và B. Tất cả các bài đăng khác dường như bỏ lỡ điểm trung tâm đó.
Doc Brown

2

Một tuyên bố chuyển tiếp là phân tích cú pháp nhanh hơn nhiều so với toàn bộ tệp tiêu đề mà chính nó có thể bao gồm nhiều tệp tiêu đề hơn.

Ngoài ra, nếu bạn thay đổi một cái gì đó trong tệp tiêu đề cho lớp B, mọi thứ bao gồm tiêu đề đó sẽ phải được biên dịch lại. Với một tuyên bố chuyển tiếp, đó chỉ có thể là tệp nguồn nơi triển khai của A đang cư trú. Nhưng nếu tiêu đề của A thực sự bao gồm tiêu đề của B, mọi thứ bao gồm a.hppcũng sẽ được biên dịch lại, ngay cả khi nó không sử dụng bất cứ thứ gì của B.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.