2011-02-09 23 views
20

Tôi đang băn khoăn một chút về công việc kinh doanh này.Làm thế nào để hòa giải thành phần C++ của việc tách tiêu đề/nguồn với các mẫu?

Trong C và C++, việc đặt các khai báo trong các tệp tiêu đề và các định nghĩa trong các tệp nguồn là rất phổ biến và giữ cho hai tệp hoàn toàn riêng biệt. Tuy nhiên, điều này thậm chí không có vẻ là có thể (trong bất kỳ cách nào tuyệt vời) khi nói đến các mẫu, và như chúng ta đều biết, các mẫu là một công cụ tuyệt vời.

Ngoài ra, Boost chủ yếu là tiêu đề, vì vậy đây là vấn đề thực sự. Việc phân tách các tiêu đề và nguồn vẫn là một ý tưởng hay trong C++, hay tôi không nên dựa nhiều vào các mẫu?

+5

Thật lố bịch khi câu hỏi này đã bị đóng. Nó rõ ràng và rõ ràng với tôi những gì đang được hỏi. Và tôi nghĩ rằng một câu trả lời cho câu hỏi này sẽ rất hữu ích để có trên trang web này. – Omnifarious

+0

@Omni: Tôi đã bỏ phiếu để đóng câu hỏi này bởi vì (IMHO) đó là sự kết hợp của một cuộc chiến tranh lửa đang chờ xảy ra, và unanswerables mở ("tôi không nên dựa nhiều vào các mẫu?"). –

+0

@Oil Charlseworth - Ahh, vâng, tôi có thể thấy rằng ngôn ngữ được sử dụng sẽ là một chút viêm. Tôi sẽ chỉnh sửa nó thành một câu hỏi trung lập hơn. – Omnifarious

Trả lời

18

Instantiating một mẫu là tốn kém tại thời gian biên dịch nhưng virtualy miễn phí trong thời gian chạy . Về cơ bản, mỗi khi bạn sử dụng một kiểu mẫu mới, trình biên dịch phải tạo mã cho loại mới đó, đó là lý do tại sao mã nằm trong một tiêu đề, để trình biên dịch có quyền truy cập vào mã sau này.

Đặt tất cả mã của bạn vào tệp .cpp cho phép trình biên dịch biên dịch mã đó chỉ một lần để tăng tốc độ biên dịch. Bạn có thể trong lý thuyết viết tất cả các mã của bạn trong tiêu đề, nó sẽ làm việc tốt, nhưng nó sẽ mất mãi mãi để biên dịch các dự án rất lớn. Ngoài ra, ngay sau khi bạn sẽ thay đổi một dòng bất cứ nơi nào, bạn sẽ phải xây dựng lại tất cả mọi thứ.

Bây giờ bạn có thể hỏi, làm cách nào mà STL và BOOST không quá chậm? Đó là nơi các tiêu đề được biên dịch sẵn đến để giải cứu. PCHs cho phép trình biên dịch thực hiện công việc tốn kém nhất chỉ một lần. Điều này làm việc tốt với mã mà sẽ không thay đổi thường xuyên như các thư viện, nhưng hiệu quả của nó là hoàn toàn vô hiệu hóa cho mã mà thay đổi rất nhiều khi bạn sẽ phải biên dịch lại toàn bộ các tiêu đề biên dịch sẵn mọi lúc. Trình biên dịch cũng sử dụng một vài thủ thuật để tránh biên dịch lại tất cả các mã mẫu trong mọi đơn vị biên dịch.

Cũng lưu ý rằng C++ 0x sẽ giới thiệu cơ chế rõ ràng để kiểm soát tốt hơn việc tạo mẫu. Bạn sẽ có thể tạo ra một cách rõ ràng các mẫu và, quan trọng nhất là ngăn chặn sự instanciation trong một số đơn vị biên dịch. Tuy nhiên, hầu hết công việc đó đã được thực hiện bởi hầu hết các trình biên dịch mà chúng ta không biết.

Vì vậy, quy tắc chung là, đặt nhiều mã (và bao gồm chỉ thị) nhất có thể trong tệp .cpp của bạn. Nếu bạn không thể, tốt, bạn không thể.

Lời khuyên của tôi sẽ là: không chỉ mẫu cho heck của nó. Nếu bạn phải mẫu, hãy cẩn thận và nhận thức được rằng bạn đang trong thực tế lựa chọn giữa tốc độ biên dịch và khả năng sử dụng các mẫu sẽ mang lại.

+0

một +1 lớn cho bạn thưa bạn. – tenfour

+1

+1 để nói: không mẫu chỉ cho heck của nó –

+0

Trong C++ 03 cũng tồn tại 'xuất khẩu 'từ khóa, nhưng nó thực hiện chỉ trong Comeau. –

7

yêu thích cá nhân của tôi là cấu trúc này:

tập tin tiêu đề:

#ifndef HEADER_FILE 
#define HEADER_FILE 

template < typename T > 
class X { void method(); }; 

#include "header_impl.h" 

#endif 

tập tin thực hiện:

#ifndef HEADER_IMPL_FILE 
#define HEADER_IMPL_FILE 

#include "header.h" 

template < typename T > 
void X<T>::method() { } 

#endif 
+3

-1 trong khi có thể, vì lý do nào đó, thông tin của bạn không hữu ích lắm mà không nói lợi thế của nó là gì và cách nó được sử dụng cho đến khi mẫu được sử dụng. (nếu có bảo vệ trên impl ngụ ý bạn đang bao gồm impl ở đâu đó, mặc dù bạn không nói như vậy, và có hai tệp được bao gồm sẽ giống như có tệp tiêu đề lớn hơn) –

+0

@Pete Uh? T không bao giờ được biết cho đến khi mẫu được sử dụng, đó là một trong những điểm chính của mẫu. Chắc chắn bạn có thể sử dụng các mẫu ngay cả đối với mã không tham số, nhưng điều đó đánh bại mục đích. Tôi quên một dòng trong mã (nó gần như dành riêng cho các công cụ mã hóa), lý do cho các vệ sĩ phải rõ ràng bây giờ. –

+0

+1, đó là những gì tôi thường làm, nhưng không bao gồm "header.h" trong "_impl.h" một lần nữa. Có thể hữu ích cho IntelliSense, nhưng không cần thiết. – Xeo

2

Tôi nghĩ điều thực sự quan trọng cần hiểu về mẫu là, diễn giải Bjarne Stroustrop, C++ thực sự giống như nhiều ngôn ngữ được cuộn thành một. Các quy ước và thành ngữ của việc tạo khuôn mẫu khác với các quy ước viết "C" thông thường, gần giống như một ngôn ngữ khác. Nó hoàn toàn là một ý tưởng tốt để phân tách các tập tin tiêu đề và thực hiện trong "thường xuyên" C++, bởi vì các tập tin tiêu đề cho trình biên dịch những gì bạn sẽ cung cấp như một thực hiện một thời gian sau đó (tại thời gian liên kết). Điều quan trọng là vì sự tách biệt này là một điều rất thực trong hầu hết các hệ điều hành phổ biến: thời gian liên kết có thể xảy ra khi người dùng chạy chương trình.Bạn có thể biên dịch việc triển khai thành các tệp nhị phân (như vậy, của dll) và gửi các tiêu đề chưa được sửa đổi cho các nhà phát triển để biết cách sử dụng triển khai hiện tại của bạn.

Bây giờ, đối với mẫu, bạn không thể làm điều đó vì trình biên dịch phải giải quyết đầy đủ mọi thứ tại thời gian biên dịch. Tức là, khi bạn biên dịch các tiêu đề, họ phải thực hiện của mẫu để trình biên dịch có thể hiểu được các tiêu đề của bạn. Trình biên dịch về cơ bản "un-templates" các mẫu của bạn khi bạn biên dịch, do đó không có tùy chọn để tách giao diện và thực hiện mẫu C++. Việc tách giao diện và triển khai là thực hành tốt, nói chung, nhưng khi bạn đi lang thang vào khuôn mẫu, bạn rõ ràng sẽ đến một nơi không thể thực hiện được - vì đó là ý nghĩa của mẫu: giải quyết và xây dựng triển khai của giao diện này tại thời gian biên dịch, không phải ở thời gian chạy.

-1

Tách tiêu đề và nguồn không phải là thành ngữ C++, nó là thành ngữ C, chính xác hơn C++ ưu tiên sử dụng mẫu và hàm nội tuyến nếu có thể giảm thời gian chạy chương trình.

+0

Bạn có thể sử dụng trình tối ưu hóa toàn bộ chương trình cho điều đó. Nếu bạn đặt quá nhiều thứ vào các tệp tiêu đề, nó sẽ làm chậm quá trình biên dịch, đặc biệt là trong các dự án không tầm thường. –

1

Dưới đây là một vài kỹ thuật tôi sử dụng khi viết mã templated di chuyển triển khai vào các tập tin cpp:

  1. Move bộ phận của phương pháp mà không phụ thuộc vào các thông số mẫu thành các hàm helper riêng biệt, không mẫu hoặc các lớp cơ sở. Các cơ quan sau đó có thể đi vào các tập tin cpp riêng của họ.

  2. Viết tờ khai chuyên môn chung. Các định nghĩa có thể sống trong các tệp cpp của riêng chúng.

Các vấn đề liên quan