2012-04-20 19 views
5

Lớp cơ sở A có một phân lớp BB có một phân lớp C. A triển khai phương thức ảo doStuff(), B không và C. Từ C, tôi muốn gọi A 'thi hành doStuff() s (Tôi làm điều này từ bên trong C' thi hành doStuff() s nhưng điều đó nên không thực sự quan trọng.) Tôi có nên gọi:Gọi các phương thức có tên giống nhau trong các lớp cơ sở

A::doStuff(); 

Hoặc:

B::doStuff(); 

Điều đầu tiên có vẻ rõ ràng hơn vì nó đề cập đến việc triển khai thực tế. Mặt khác, thứ hai có thể hữu ích hơn nếu sau này tôi quyết định rằng B cần phải doStuff() khác với A. Tiêu chuẩn nào hơn? Điều gì nguy hiểm hơn?

Tôi hơi ngạc nhiên khi B::doStuff() không kích hoạt bất kỳ cảnh báo nào, nhưng tôi cho rằng theo định nghĩa B có triển khai ngay cả khi nó thuộc lớp cơ sở. Chuỗi các lớp cơ sở và triển khai có thể tùy ý lâu dài và phức tạp không? Ví dụ, nếu tôi có A thông qua Z, mỗi lớp con của lớp trước, tôi có thể triển khai ở bất kỳ vị trí nào trong chuỗi không, và gọi phương thức của bất kỳ lớp nào chỉ cần đi 'lên chuỗi' cho đến khi nó tìm thấy triển khai?

Trả lời

2

Đầu tiên, liên quan đến đoạn cuối, vâng, bạn hoàn toàn đúng.

Tiếp theo, đối với câu hỏi chính:

Đó là vấn đề logic cần được xử lý theo từng trường hợp. Bạn là người duy nhất có thể quyết định xem bạn có muốn gọi logic từ B hoặc từ A, ngay cả khi B::doStuff() chưa được triển khai. Không có câu trả lời đúng.

Tuy nhiên, bạn nên xem xét phương thức mẫu mẫu mẫu. Tôi đoán là nếu bạn muốn C để gọi một cái gì đó từ A và sau đó bạn quyết định rằng bạn muốn D (anh chị em của C) để làm điều tương tự, bạn đang sao chép mã. Vì vậy, tôi có cách tiếp cận khác:

class A 
{ 
private: 
    void doAStuff(); //doesn't have to be here 
public: 
    virtual void doStuff() 
    { 
     doAStuff(); 
    } 
    void doAStuffAndStuff(); 
    { 
     doAStuff(); 
     doStuff(); 
    } 
} 

class B : A 
{ 
public: 
    virtual void doStuff(); //or not 
} 

class C : B 
{ 
public: 
    virtual void doStuff(); 
} 

IMO này trực quan hơn. Nói rằng tôi có một A* a, tôi không biết loại năng động của a:

  • nếu tôi muốn gọi doStuff() với logic trong lớp có nguồn gốc nhất, tôi gọi doStuff().
  • nếu tôi muốn gọi doStuff() với logic trong lớp có nguồn gốc cao nhất, nhưng tôi cũng muốn logic từ A, tôi gọi doAStuffAndStuff().

Tôi đang nói phương pháp này là phương án thay thế. Tôi không nói nó nhất thiết phải áp dụng cho trường hợp của bạn, nhưng nó có thể.

+0

Điều đó trông giống như một lựa chọn rất gọn gàng và hữu ích. – Luke

0

Gọi B::doStuff. Thậm chí tốt hơn, không sử dụng các thiết kế đòi hỏi phải gọi các phương thức của các lớp cơ sở một cách rõ ràng, nếu bạn có thể.Nếu bạn phải, mô phỏng base.doStuff bởi một số cấu trúc macro hoặc bí danh để ngăn chặn chính xác loại lỗi đó. Bạn có thể xác định một bí danh (và đảm bảo sự hiện diện của nó tại thời gian biên dịch) BaseType ở lớp và sử dụng cú pháp BaseType::doStuff.

Tôi là một chút ngạc nhiên rằng B :: doStuff() không gây ra bất kỳ cảnh báo, nhưng tôi cho rằng theo định nghĩa B có thực hiện ngay cả khi đó là từ các lớp cơ sở

Có không có gì để cảnh báo. Đó là trong trường hợp của bạn một kịch bản pháp lý.

chuỗi các lớp cơ sở và triển khai có thể được tùy tiện lâu và phức tạp

Có nó có thể, nhưng nó không nên. Các kiểu dáng yêu cầu các chuỗi kế thừa dài cộng với chứa một số kiểu quy tắc ẩn nào mà các phương thức của lớp cơ sở nào nên được gọi là thường bị hỏng.