2010-10-25 30 views
15

Các dữ kiện:Thông tư phụ thuộc trong C++

  • Tôi có hai lớp học chủ yếu: Quản lý và Chuyên viên.
  • Có một số loại Chuyên gia khác nhau.
  • Các chuyên gia thường yêu cầu sự giúp đỡ của các Chuyên gia khác để hoàn thành công việc của họ.
  • Người quản lý biết tất cả các Chuyên gia và ban đầu mỗi Chuyên gia chỉ biết Người quản lý của họ. (Đây là vấn đề.)
  • Khi chạy, Trình quản lý tạo và lưu trữ danh sách Chuyên gia. Sau đó, Người quản lý lặp lại qua danh sách và yêu cầu mỗi Chuyên gia khởi tạo. Trong quá trình khởi tạo, mỗi Chuyên gia yêu cầu Người quản lý cung cấp cho họ các Chuyên gia khác thực hiện một số mô tả. Khi điều này hoàn tất, Trình quản lý sẽ đi vào một vòng lặp trong đó các Chuyên gia được hỏi tuần tự để thực hiện nhiệm vụ chuyên môn của họ.

Với tôi có vẻ như đây là một mẫu khá, nhưng vì một người quản lý có danh sách các chuyên gia và một chuyên gia có một người quản lý tôi nhận được các vấn đề phụ thuộc vòng tròn.

Đây có phải là trường hợp mà tôi nên bằng cách nào đó chuyển tiếp tuyên bố sự tồn tại của một lớp học từ lớp khác? (Nếu vậy, làm thế nào?) Hoặc tôi nên sử dụng một số mẫu thiết kế để khắc phục vấn đề này? (Nếu có thì sao?) Ngoài ra ... tôi mặc dù bản thân mẫu hình này khá o.k. vì vậy tôi sẽ không nhớ ai đó giúp tôi hiểu tại sao đây là một điều xấu.

+0

Bạn có thể cho chúng tôi biết một ví dụ về những gì bạn có và chính xác những vấn đề bạn gặp phải không? –

+0

Tôi đã nhìn thấy câu hỏi tương tự này được hỏi nhiều lần gần đây - đây là câu hỏi gần đây nhất http://stackoverflow.com/questions/4016471/c-circular-reference-problem –

+0

@Greg - Các câu hỏi tương tự, tuy nhiên tôi quan tâm đến việc không chỉ giải quyết sự phụ thuộc vòng tròn, mà còn hiểu được liệu tôi có đang sử dụng mẫu đó nếu thiếu sót vì một lý do nào đó không. – JnBrymn

Trả lời

23

Trong cả hai trường hợp, phía trước khai báo lớp khác:

Manager.h

class Specialist; 

class Manager 
{ 
    std::list<Specialist*> m_specialists; 
}; 

Specialist.h

class Manager; 

class Specialist 
{ 
    Manager* m_myManager; 
}; 

Thời gian duy nhất bạn cần phải mang theo các tập tin tiêu đề cho một lớp là khi bạn cần phải sử dụng một hàm thành viên hoặc biến trong lớp đó, hoặc cần phải sử dụng lớp như một kiểu giá trị vv Khi bạn chỉ cần một con trỏ hoặc tham chiếu đến một lớp, một khai báo chuyển tiếp sẽ là đủ.

Lưu ý rằng các khai báo chuyển tiếp không chỉ để giải quyết các phụ thuộc vòng tròn. Bạn nên sử dụng các khai báo chuyển tiếp bất cứ khi nào có thể. Chúng là luôn luôn thích hợp hơn để bao gồm một tệp tiêu đề phụ nếu nó hoàn toàn khả thi.

+4

+1 - "tuyên bố chuyển tiếp" là các từ khóa – leonbloy

+4

"Chúng luôn thích hợp hơn" Tôi _strongly_ không đồng ý và cho rằng chúng _rarely_ thích hợp hơn ở bất kỳ nơi nào có thể tránh được. Việc sử dụng các khai báo chuyển tiếp trong một lớn làm cho việc hiểu mã khó hiểu hơn vì nó trở nên khó khăn hơn để theo dõi các phụ thuộc. Hơn nữa, thường có ít hoặc không có hiệu suất đạt được khi sử dụng một trình biên dịch hiện đại mà lưu trữ các tập tin tích cực và hỗ trợ các tiêu đề biên dịch trước. [Trên một lưu ý không liên quan, tại sao bạn đề nghị 'std :: list'?] –

+3

Theo dõi những phụ thuộc nào? Nếu khai báo chuyển tiếp hoạt động thì không còn phụ thuộc nữa. Ngoài ra, nó chỉ là dễ dàng để làm theo một đường mòn lớp như là một đường mòn tiêu đề trong bất kỳ IDE nửa chừng phong nha. Đối với việc sử dụng 'std :: list', anh ta nói trong OP rằng Manager lưu trữ một danh sách các chuyên gia, vì vậy tôi quyết định giải thích điều đó theo đúng nghĩa đen. Tôi có lẽ sẽ sử dụng một 'vector' bản thân mình, nhưng tất nhiên nó phụ thuộc vào các trường hợp sử dụng cụ thể. –

1

Một lựa chọn là để chuyển tiếp tuyên bố một trong những người, như bạn đề nghị:

struct specialist; 

struct manager 
{ 
    std::vector<std::shared_ptr<specialist> > subordinates_; 
}; 

struct specialist 
{ 
    std::weak_ptr<manager> boss_; 
}; 

Tuy nhiên, nếu bạn kết thúc có nhiều hơn một cây cấu trúc (nơi bạn có nhiều lớp quản lý, một person lớp cơ sở cũng sẽ làm việc:

struct person 
{ 
    virtual ~person() { } 
    std::weak_ptr<person> boss_; 
    std::vector<std::shared_ptr<person> > subordinates_; 
}; 

sau đó, bạn có thể lấy được các lớp học đặc biệt với nhiều loại người khác nhau trong hệ thống phân cấp hay không bạn cần điều này phụ thuộc vào chính xác làm thế nào bạn có ý định sử dụng các lớp

..

Nếu triển khai của bạn không hỗ trợ std::shared_ptr, nó có thể hỗ trợ std::tr1::shared_ptr hoặc bạn có thể sử dụng boost::shared_ptr.

+0

trong mô hình này, bạn có phải đảm bảo rằng tất cả các con trỏ 'manager' được gói trong' shared_ptr'? Nếu không thì không có cách nào để xác thực 'weak_ptr' có ở đó không? Tò mò về điều này vì nó đến rất nhiều cho tôi. –

+0

@Steve: Có. Sẽ dễ dàng hơn nhiều nếu bạn chỉ có một loại lớp trong cấu trúc phân cấp (như 'person' trong ví dụ thứ hai của tôi). –

1

đây là nội dung thông thường. Bạn chỉ cần

class Manager; 

trong tiêu đề chuyên và

class Specialist; 

trong tiêu đề quản lý

nếu bạn đang sử dụng shared_ptrs bạn có thể thấy shared_from_this hữu ích. (Không phải cho Looping nhưng vì có vẻ như bạn sẽ cần nó anyway)

8

Đó là vấn đề về hương vị, nhưng tuyên bố chuyển tiếp thường là một lựa chọn tốt để bao gồm trong tệp tiêu đề ngay cả khi không phụ thuộc vòng tròn. (Tôi không muốn nêu lên một cuộc thảo luận về điều đó ở nơi này.) Vì vậy, đây là một ví dụ về cách áp dụng tờ khai phía trước cho vấn đề của bạn:

Trong Manager.h:

// Forward declaration: 
class Specialist; 

// Class declaration: 
class Manager 
{ 
    // Manager declarations go here. 
    // Only pointers or references to 
    // the Specialist class are used. 
}; 

Trong Manager.cpp:

#include "Specialist.h" 

// Manager definitions/implementations 
// using the Specialist class go here. 
// Full Specialist functionality can be used. 

Ở Specialist.h:

// Forward declaration: 
class Manager; 

// Class declaration: 
class Specialist 
{ 
    // Specialist declarations go here. 
    // Only pointers or references to 
    // the Manager class are used. 
}; 

Ở Specialist.cpp:

#include "Manager.h" 

// Specialist definitions/implementations 
// using the Manager class go here. 
// Full Manager functionality can be used. 
+0

Cảm ơn ví dụ rõ ràng, đó là câu trả lời hữu ích duy nhất về điều này cho đến nay! – fuenfundachtzig

1

Trong khi mọi người khác trả lời câu hỏi cốt lõi tôi nghĩ tôi sẽ chỉ ra điều này.

Khi chạy, Trình quản lý tạo và lưu trữ danh sách Chuyên gia. Sau đó, Người quản lý lặp lại qua danh sách và yêu cầu mỗi Chuyên gia khởi tạo. Trong quá trình khởi tạo, mỗi Chuyên gia yêu cầu Người quản lý cung cấp cho họ các Chuyên gia khác thực hiện một số mô tả. Khi điều này hoàn tất, Trình quản lý sẽ đi vào một vòng lặp trong đó các Chuyên gia được hỏi tuần tự để thực hiện nhiệm vụ chuyên môn của họ.

Tôi chỉ muốn chỉ ra rằng điều này cần phải là quy trình gồm hai bước. Làm cách nào người quản lý có thể nói với chuyên gia 1 những chuyên gia nào tồn tại cho nhiệm vụ B nếu người quản lý chỉ biết về một chuyên gia cho đến nay? Vì vậy, bạn cần:

1) người quản lý đi qua danh sách các chuyên gia và yêu cầu họ tự xác định.

2) người quản lý đi qua danh sách các chuyên gia và hỏi họ những đặc sản nào họ cần truy cập, cho họ biết ai có thể đáp ứng yêu cầu của họ.

3) người quản lý đi qua danh sách các chuyên gia và yêu cầu họ thực hiện hành động của họ.

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