2011-11-02 34 views
10

Trong C++ và Objective-C, tôi đã có thói quen chuyển tiếp bất kỳ lớp cần thiết nào không cần phải được xác định trong tiêu đề, sau đó nhập tệp tiêu đề xác định các lớp đó trong tệp nguồn nếu cần.Nhược điểm của việc khai báo chuyển tiếp?

Có bao giờ xảy ra tình huống trong đó đây không phải là một ý tưởng hay không?

(Tôi biết bất lợi lớn của việc khai báo chuyển tiếp là khả năng sử dụng hạn chế của một kiểu không đầy đủ. Vì mục đích của câu hỏi này, giả sử rằng trong tiêu đề tôi chỉ cần sử dụng lớp được khai báo phía trước như một kiểu không đầy đủ.)

+17

Ít cơ hội uống cà phê trong khi xây dựng đầy đủ? –

Trả lời

6

Đôi khi bạn có thể thay đổi ngữ nghĩa của chương trình một cách tinh tế mà không tăng bất kỳ lỗi nào

class Foo; 

template < typename T> 
struct Trait 
{ 
    static const int MY_TYPE = -1; 
}; 

// Lets say this is Foo.h 
//class Foo 
//{ 
//}; 
//template<> 
//struct Trait<Foo> 
//{ 
// static const int MY_TYPE = 1; 
//}; 

void TestFunction(Foo& f) 
{ 
    std::cout << Trait<Foo>::MY_TYPE << std::endl; 
} 

Hãy xem xét đoạn mã trên và mã nhận xét ra sống trong một tiêu đề. Nếu tiêu đề được bao gồm TestFunction sẽ in 1 cách khác -1

+0

+1 .. Có thể áp dụng nhiều hơn bình luận của tôi biết những gì tôi biết bây giờ về quá trình suy nghĩ của OP. – Steve

+0

Thú vị. Đó là thứ tôi tò mò. – Luke

3

Một bất lợi có thể là thiếu thông tin ẩn/đóng gói.

Tôi muốn có tệp tiêu đề tối thiểu nhất có thể. Điều đó có nghĩa là tôi không bắt buộc phải tiếp tục hỗ trợ rất nhiều tính năng. Nếu tôi muốn thay đổi một cái gì đó, và cái gì đó đã không được tiếp xúc trong tiêu đề công cộng, có một cơ hội tốt hơn tôi có thể thay đổi nó trong nội bộ để lớp mà không ảnh hưởng đến bất cứ ai khác.

EDIT:

Luke hỏi cho một ví dụ, vì vậy đây ya đi:

Giả sử bạn có một lớp được gọi là Car. Và, điều duy nhất bạn xây dựng nó là lấy từ điểm A đến điểm B. Tôi, cá nhân, tôi muốn giữ tập tin tiêu đề của tôi: một lớp được gọi là Car và một phương thức có tên là Drive. Từ cách bạn diễn đạt câu hỏi của bạn ("tất cả các lớp mà tôi có thể") tôi mong đợi sẽ tìm các lớp như "DieselEngine", "PetrolEngine", "HybidEngine" và như vậy trong tệp tiêu đề của bạn. Vấn đề với điều này là những người khác làm việc trong dự án của bạn (hoặc, bạn, theo thời gian) bắt đầu sử dụng những lớp tiếp xúc đó. Bây giờ, hai năm sau, bạn quyết định "Hrm ... lớp học của PetrolEngine thực sự gây ra vấn đề cho tôi. Tôi nghĩ tôi sẽ loại bỏ nó và thay thế nó bằng HybridEngine hoàn toàn trong lớp xe của tôi" - vâng, bây giờ là PetrolEngine được bao gồm trong 100 tệp khác vì lý do bạn không hiểu - và bây giờ bạn buộc phải giữ cho PetrolEngine xung quanh (và làm việc như trước đây) cho tất cả những người khác đã sử dụng nó trong một số nói rằng bạn không thực sự chắc chắn về - bởi vì bạn không có "hợp đồng" vững chắc về cách bạn muốn lớp đó được sử dụng ngay từ đầu. Đó là một chi tiết thực hiện những gì bạn thực sự muốn thực hiện - xây dựng một chiếc xe hơi.

EDIT để thảo luận ý kiến ​​về ẩn thông tin:

Nếu tất cả các bạn đang làm là đúng về phía trước khai khống tên lớp/struct - tốt, tôi đoán tôi sẽ hỏi "tại sao" một lần nữa. Nếu tôi là người tiêu dùng tệp và lớp tiêu đề của bạn và tôi không thể thực hiện bất kỳ điều gì với lớp đó - và nó không được hiển thị dưới dạng tham số hoặc kiểu trả về của API lớp chính của bạn - thì tại sao lại hiển thị nó ?

Nếu bạn đang sử dụng nó để kiểm tra an toàn loại thời gian biên dịch cho cấu trúc dữ liệu mờ - tốt - đó là một điều. Tuy nhiên, cách bạn phrased câu hỏi của bạn làm cho nó âm thanh với tôi như tất cả mọi thứ đã đi trong tập tin tiêu đề như là một vấn đề của khóa học.

+0

Tôi không chắc mình biết ý của bạn là gì. Bạn có thể đưa ra một ví dụ? – Luke

+4

Kỹ thuật này có giúp tăng cường ẩn thông tin không? Có rất ít thông tin trong một tờ khai chuyển tiếp hơn là trong một tuyên bố đầy đủ. –

+2

Bạn có thể giải thích cách các tờ khai chuyển tiếp phá vỡ đóng gói không? Dường như với tôi rằng chỉ cung cấp tên lớp ẩn nhiều thông tin hơn là cung cấp định nghĩa đầy đủ. –

0

Không, theo như tôi biết. Điều bất lợi duy nhất mà bạn đã đề cập đến là sử dụng các loại không đầy đủ. Vì bạn nói rằng sẽ không có bất kỳ tập quán nào cần các loại được xác định đầy đủ, bạn sẽ ổn.

0

Tuyên bố chuyển tiếp được ưu tiên để đưa vào tệp đầy đủ nếu bạn không cần toàn bộ định nghĩa của lớp trong tiêu đề.Bất lợi duy nhất tôi có thể nghĩ là đã được đăng tải như một bình luận của @Stephen Darlington mà tôi sẽ đưa ra 10 upvotes nếu tôi có thể. :)

0

Một bất lợi là rò rỉ bộ nhớ tiềm năng trong các loại được khai báo chuyển tiếp. Xem this question để biết thêm chi tiết. Microsoft compilers issue warning C4150: deletion of pointer to incomplete type 'SomeType'; no destructor called trong trường hợp này.

+2

Không phải là vấn đề với trình biên dịch thực. –

2

Tuyên bố chuyển tiếp có thể được áp dụng cho nhiều thứ: lớp, hàm, biến toàn cầu/hằng số (sử dụng extern) và trong C++ 11, enums.

Những bất lợi chính, như xa như tôi thấy, là sự thừa, vì dự phòng giới thiệu phạm vi nhiều hơn cho các lỗi, tuy nhiên điều này áp dụng rất khác nhau tùy thuộc vào những gì bạn đang chuyển tiếp tuyên bố.

Nếu bạn có lỗi với khai báo chuyển tiếp của một lớp, một toàn cầu hoặc một enum, trình biên dịch sẽ lấy nó lên (vâng!).

Nếu bạn có lỗi với khai báo hàm, thì trong C++ bạn vừa tạo ra một tình trạng quá tải (oups!).

Do đó, tôi sẽ nói rằng không có bất lợi thực sự để chuyển tiếp các lớp khai báo, hình cầu hoặc enums; Tuy nhiên, khi nói đến chức năng, tốt hơn nếu bạn gắn bó với #include, bạn luôn có thể tạo tiêu đề nhóm các chức năng liên quan để tránh tạo quá nhiều tệp.

0

Nó có lẽ là một câu hỏi dễ đọc cho các đồng nghiệp của bạn, những người sẽ phải tiếp tục công việc mã hóa của bạn.

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