2013-04-05 12 views
16

Tôi có một lớp B, và tôi muốn gọi các thành viên hình thành lớp A. Vì vậy:Bao gồm trong tập tin tiêu đề vs forward-kê khai, bao gồm trong cpp

1.

//A.h  
class B; 
class A 
{ 
private: 
    B* m_p; 
}; 

//a.cpp 
#include "B.h" 

2.

// A.h 
#include "B.h" 

class A 
{ 
private: 
    B * impl_; 
}; 

cách nào tốt hơn và hai điều này có giống nhau khi một dự án nhỏ không phụ thuộc quá nhiều không?

+0

làm như: '#include" B.h "' –

+0

à, tôi sẽ cẩn thận ... – colddie

Trả lời

23

cách đầu tiên của bạn làm việc đó có nghĩa là trong a.h, sự tồn tại của class B được biết đến, nhưng không phải là định nghĩa của nó . Điều này giới hạn những gì bạn có thể làm với B bên trong a.h. Ví dụ, bạn có thể có các biến kiểu B *, nhưng không phải là biến kiểu B (vì khai báo biến kiểu B trình biên dịch phải có khả năng xem định nghĩa đầy đủ của B). Ngoài ra, nếu bạn có các biến loại B *, bạn không thể dereference con trỏ (vì cho rằng, quá, định nghĩa của B phải được biết).

Vì vậy, lựa chọn thứ hai của bạn – không có vấn đề này – được ưu tiên và đây là điều mà hầu hết mọi người sử dụng hầu hết thời gian.

Đó chỉ là trường hợp đặc biệt mà phương pháp đầu tiên có thể hữu ích. Ví dụ:

  • Nếu .h file bao gồm nhau (nhưng sau đó bạn có thể nhận được một số vấn đề hơn nữa, cũng liên quan đến bao gồm-bảo vệ, điều này nói chung là rất khó khăn và cần phải tránh);
  • Nếu b.h là cực kỳ lớn và phức tạp, vì vậy bạn muốn tránh bao gồm nó bất cứ nơi nào có thể bởi vì nó làm chậm quá trình biên dịch.
0

Chỉ cần khai báo lớp trong tiêu đề lớp A của bạn.

class B; 
0

Thứ hai là tốt hơn. Nó làm cho lớp học B một mô-đun mà bạn bao gồm bằng cách sử dụng tệp .h. Hãy xem xét trường hợp bạn phân lớp B trong tương lai và bạn cập nhật A để sử dụng C. Trong trường hợp thứ hai, bạn chỉ thay thế tiêu đề trang điểm #includeA. Trong trường hợp đầu tiên, bạn phải thay đổi tờ khai chuyển tiếp. Ngoài ra, trong trường hợp thứ hai, bạn xác định nhiều hơn chỉ là biểu tượng B.

Và như trong nhận xét, bạn nên sử dụng #include "B.h" nếu tệp tiêu đề nằm trong cùng thư mục với phần còn lại của mã.

0

Vâng những gì bạn đang làm được gọi là chuyển tiếp decleration, lý do bạn muốn đó là nếu bạn có một cái gì đó giống như hạng A có sử dụng lớp B và CŨNG lớp B có sử dụng lớp A.

Trong một trường hợp chỉ có một mối quan hệ bạn chắc chắn có thể sử dụng lựa chọn thứ hai của bạn. Nếu bạn cần sử dụng gấp đôi, thì ít nhất một trong các cách giải mã lớp học của bạn sẽ phải sử dụng giải mã chuyển tiếp

7

Trả lời: .
Hãy xem http://www.umich.edu/~eecs381/handouts/handouts.html

C Header File Guidelines

C++ Header File Guidelines (David Kieras, EECS Phòng, Đại học Michigan) nói:

Hướng dẫn # 10. Nếu khai báo không đầy đủ của loại X sẽ làm, hãy sử dụng thay vì #bao gồm tiêu đề X.h. Nếu cấu trúc khác hoặc loại loại X chỉ xuất hiện dưới dạng con trỏ hoặc loại tham chiếu trong nội dung của một tiêu đề, thì bạn không nên #include Xh, mà chỉ cần đặt một khai báo không hoàn chỉnh X ( X)) gần phần đầu của tiêu đề, như trong: class X; Xem bản phát hành Incomplete Declarations để thảo luận thêm về kỹ thuật có giá trị mạnh mẽ này và . Lưu ý rằng Thư viện chuẩn bao gồm tiêu đề các khai báo không đầy đủ thường được cung cấp cho thư viện <iostream> , có tên <iosfwd>. #include <iosfwd> bất cứ khi nào có thể, bởi vì tiêu đề <iostream> là rất lớn (mẫu khổng lồ!).

12

Phương pháp đầu tiên của bạn là khai báo chuyển tiếp.Nhóm thứ hai của bạn thực sự bao gồm lớp B.

Khi nào sử dụng cái kia?

Sử dụng đầu tiên một khi:

  • Trong định nghĩa của A, bạn chỉ có một con trỏ đến B, tức là không phải là một thành viên của B.
  • Bạn không bao giờ gọi bất kỳ chức năng của B từ định nghĩa của A. (nghĩa là tất cả các cuộc gọi đến các hàm thành viên của B xảy ra trong tệp .cpp nơi bạn thực sự thực hiện các chức năng thành viên của A.)
  • Bạn mong đợi giao diện hoặc kích thước của lớp B thay đổi thường xuyên, nhưng không phải giao diện của A. Bằng cách này, nếu B thay đổi, chỉ có nội dung của a.cpp được biên dịch lại, nhưng a.h (và các tệp khác bao gồm a.h) không cần thay đổi.

Sử dụng thứ hai khi:

  • Bạn cần phải biết kích thước của B. Trình biên dịch sẽ tính toán kích thước của một lớp sử dụng định nghĩa các lớp học và các kích thước của tất cả các thành viên. Ví dụ, nếu lớp A có một thành viên thuộc loại B, thì để tính kích thước của A, trình biên dịch cần biết kích thước của B; để biết kích thước của B, bạn cần phải bao gồm b.h.
    • Bạn cần gọi các chức năng của lớp B. Để biết bạn đang gọi các hàm thực sự tồn tại, trình biên dịch cần biết giao diện của lớp B, tức là bạn cần bao gồm b.h.