Kịch bản trong thế giới thực cho các phương thức được bảo vệ


14

Hôm nay tôi nhận thấy rằng về cơ bản tôi không bao giờ sử dụng protectedcác phương thức trong mã C ++, bởi vì tôi hiếm khi cảm thấy cần phải gọi các phương thức không công khai của cha mẹ. Tôi sử dụng được bảo vệ trong Java trong mẫu phương thức mẫu, nhưng vì bạn có thể ghi đè các phương thức riêng tư trong C ++, nên tôi cũng không cần protectedở đó.

Vì vậy, một số tình huống trong thế giới thực mà tôi muốn sử dụng protectedcác phương thức trong mã C ++ là gì?

(Lưu ý rằng tôi không quá thích kế thừa thực hiện nói chung, điều đó có thể giải thích rất nhiều ...)

Câu trả lời:


12

Đây là một ví dụ

class Base {
public:
  // other members ...

protected:
  ~Base() { }
};

Được sử dụng như một lớp cơ sở không đa hình. Nhưng người dùng sẽ không được phép gọi delete baseptr;nó vì bộ hủy không thể truy cập được. Vì nó không có hàm hủy ảo, cho phép mọi người thực hiện điều đó sẽ là hành vi không xác định. Xem "Ảo" của Herb.


1
Có chuyện gì với các bạn vậy? Tại sao điều này bị hạ cấp? Nó hoàn toàn hợp lý. Nếu bạn không hiểu nó, xin vui lòng hỏi. Nếu bạn cảm thấy như vậy là sai, xin vui lòng giải thích. Chúng tôi ở đây để học hỏi từ những hiểu biết của bạn.
sbi

Tại sao -1? Đây là điều đầu tiên tôi nghĩ đến.
GManNickG

1
Các nhà xây dựng và phá hủy là về những công dụng duy nhất tôi từng thấy. Lưu ý rằng gcc vẫn phát ra cảnh báo rằng hàm hủy không ảo trên cái này.
Matthieu M.

+1 Tôi cũng sử dụng phương pháp được bảo vệ để áp dụng một số lời khuyên về sách: có giao diện chung với các chức năng ảo được bảo vệ, thay vì các chức năng ảo công khai.
Klaim

3

Một ví dụ mà tôi sử dụng thường xuyên là trong Lớp cơ sở của Phân cấp đối tượng của tôi, tôi sẽ có một Trình ghi nhật ký được bảo vệ. Tất cả các lớp cơ sở của tôi sẽ cần quyền truy cập vào Logger, nhưng không có lý do gì để làm cho nó có thể truy cập công khai.

Ngoài ra, nếu bạn đang sử dụng mẫu Mẫu và bạn có phương thức thực thi trước hoặc sau trên lớp cơ sở, bạn có thể muốn gọi triển khai cơ sở từ phương thức ghi đè. Nếu cơ sở chỉ là riêng tư (và vẫn có thể được ghi đè trong C ++), bạn sẽ không thể gọi triển khai cơ sở từ phương thức ghi đè.


1
Không phải mẫu tất cả về việc không phải gọi các phương thức lớp cơ sở sao ???
sbi

Quan điểm, nhưng tôi sẽ không nói rằng 'tất cả' về việc không phải gọi các phương thức lớp cơ sở. Trong nhiều tình huống, tôi có hệ thống phân cấp đối tượng triển khai mẫu mẫu có nhiều cấp độ, mỗi cấp độ sẽ thêm nhiều chức năng / kiểm tra hơn một chút. Trong những trường hợp này, một phương pháp được bảo vệ sẽ là cần thiết.
bryanatkinson

1

Chỉ là một ví dụ tôi đã sử dụng trong quá khứ. Các phương thức được bảo vệ là tuyệt vời để cung cấp các chức năng dành riêng cho việc triển khai, đồng thời cho phép lớp cơ sở theo dõi đúng mọi thứ. Hãy xem xét một lớp cơ sở cung cấp hàm khởi tạo có thể ghi đè, nhưng cũng phải có trạng thái để xác định nếu được khởi tạo:

class Base
{
private:
    bool m_bInitialized;
public:
    virtual void Initialize() = 0;

    void setInitialized() { m_bInitialized = true; };
    bool isInitialized() const { return m_bInitialized; };
}; // eo class Base

Tất cả đều tốt và tốt ở đây. Ngoại trừ khi một lớp dẫn xuất không bận tâm gọi setInitialized()ít nhất là thực tế là bất kỳ ai cũng có thể gọi nó (chúng ta có thể làm cho điều này được bảo vệ ở đây và một lý do khác để sử dụng các phương thức được bảo vệ!). Tôi rất thích một lớp sử dụng các thành viên được bảo vệ ảo:

class Base
{
private: 
    bool m_bInitialized;

protected:
    virtual void InitializeImpl() = 0;

public:

    void Initialize()
    {
        InitializeImpl();
        m_bInitialized = true;
    }; // eo Initialize

    bool isInitialized() const { return m_bInitialized; };
}; // eo class Base

Trong lớp mới của chúng tôi, tất cả các khởi tạo vẫn được ủy quyền cho lớp dẫn xuất. Cung cấp một ngoại lệ như đã được ném, chúng tôi duy trì hợp đồng "lớp này được khởi tạo" mà phương thức của chúng tôi nói sẽ xảy ra.


0

Như nhiều tính năng khác, protectedcho phép bạn phá vỡ đóng gói đến một số mở rộng. Phá vỡ các khái niệm OO thuần túy thường được thực hiện vì nhiều lý do

  1. đạt được hiệu suất tốt hơn (nghĩ inline),
  2. làm cho mã dễ hiểu hơn và trớ trêu thay
  3. đóng gói tốt hơn ( friendcho phép bạn hạn chế quyền truy cập vào các thành viên trong lớp cho một vài người bạn)

protectedchỉ là một trong những công cụ trong hộp đó. Bạn có thể sử dụng nó nếu bạn muốn cấp cho các lớp dẫn xuất quyền truy cập vào một số phần của một lớp nên được ẩn khỏi công chúng.

Một trường hợp mà tôi đã sử dụng nó là làm cho tất cả các hàm tạo của một lớp protected, về cơ bản làm cho lớp đó trở nên trừu tượng (bạn không thể khởi tạo nó ngoại trừ như một đối tượng phụ của một đối tượng của lớp dẫn xuất).


0

Có lẽ đó là thiết kế tồi, nhưng tôi đã có nó cho một cái gì đó như thế này:

// much simplified, of course
class input_device // base class
{
public:
    virtual ~input_device() {}

    // normally would be private with public caller, etc.
    virtual void update() = 0; 

    template <typename Func>
    void register_callback(Func func)
    {
        mButtonPressSignal.connect(func);
    }

protected:
    void trigger_signal(unsigned button)
    {
        mButtonPressSignal(button);
    }

private:
    boost::signals2::signal<void(unsigned)> mButtonPressSignal;
};

Các lớp dẫn xuất, trong update(), có thể kích hoạt tín hiệu bằng cách gọi trigger_signal(). Nhưng vì đó là tất cả những gì họ có thể làm với tín hiệu, nên tín hiệu được giữ riêng tư. Hàm kích hoạt đã được bảo vệ vì chỉ có lớp dẫn xuất mới có thể kích hoạt nó, không phải bất cứ thứ gì cả.


0

"Phương thức công cộng": Một lớp có thể làm điều này. "Phương thức được bảo vệ": Làm thế nào một lớp có thể làm điều này. "Phương pháp riêng tư": Làm thế nào một lớp có thể làm điều này, nhưng "Tôi bị hoang tưởng và không muốn ai biết tôi làm như thế nào".

// burguers.hpp

class BurguerClass {
  private: void addSecretRecipeSauce();  

  protected: virtual void addBread();  
  protected: virtual void addSalad();  
  protected: virtual void addMeat();
  protected: virtual void addExtraIngredients();

  public: virtual void makeBurguer();  
}

class CheeseBurguerClass: public BurguerClass {
  protected: override void addBread();  
  protected: override void addSalad();  
  protected: override void addMeat();
  protected: override void addExtraIngredients();

  protected: virtual void addCheese();

  public: override void makeBurguer();
}

class RanchStyleBurguerClass: public BurguerClass {
  protected: override void addBread();  
  protected: override void addSalad();  
  protected: override void addMeat();
  protected: override void addExtraIngredients();

  public: override void makeBurguer();
}

class EastCoastVegetarianStyleBurguerClass: public BurguerClass {
  protected: override void addBread();  
  protected: override void addSalad();  
  protected: override void addMeat();
  protected: override void addExtraIngredients();

  public: override void makeBurguer();
}

Vì vậy, một đầu bếp mới (nhà phát triển) đến nhà hàng thức ăn nhanh của bạn. Bạn dạy nó, bạn bán bánh mì kẹp thịt (phương pháp công cộng), cách chuẩn bị bánh mì kẹp thịt (phương pháp được bảo vệ), nhưng giữ nước sốt công thức bí mật "được cấp bằng sáng chế" cho chính bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.