簡體   English   中英

這兩個類是否違反了封裝?

[英]Do these two classes violate encapsulation?

class X
{
protected:
    void protectedFunction() { cout << "I am protected" ; }
};

class Y : public X
{
public:
    using X::protectedFunction;
};

int main()
{
    Y y1;
    y1.protectedFunction();
}

這樣我就可以公開基類的一個功能。

  1. 這不違反封裝原則嗎?
  2. 是否有一個特定的原因,為什么這是標准的?
  3. 是否有任何用途,或者是否會在新標准中進行更改?
  4. 標准中是否存在與此相關的未解決問題?

你是自己做的。
你可以寫

class Y : public X
{
public:
    void doA()
    {
       protectedFunction();
    }
};

int main()
{
    Y y1;
    y1.doA(); 
}

我認為沒有理由擔心它。
受保護的函數是繼承樹中可重用邏輯的一部分。 你可以隱藏它們,如果有一些內部邏輯或限制,或者像你的情況那樣你可以暴露它,如果你確定這不會傷害任何人。

是的,這就是為什么受保護已經受到了公平的批評。

C ++的創建者Bjarne Stroustrup在他的優秀着作“C ++的設計和演變”中對此感到遺憾:

我對受保護的一個擔憂正是因為它太容易使用一個共同的基礎,就像人們可能已經習慣使用全局數據一樣....回想起來,我認為受保護是一個“好的論據”和時尚克服的情況我更好的判斷力和接受新功能的經驗法則。

我認為正是Stroustrup本人說C ++中內置的封裝和數據完整性功能旨在讓誠實的人保持誠實,而不是阻止犯罪分子。

編號protectedFunction()受保護。 您可以從派生類中自由調用它,因此您可以直接從Y的公共成員調用它,並從main()調用此公共成員。

如果您可以使用私有方法完成此操作,則會出現問題...(編輯更清楚一點)。

從語言的角度來看,與在派生對象中創建委托方法相比,這不僅僅是對封裝的違反:

class Y : public X
{
public:
    void protectedFunction() {
       X::protectedFunction();
    }
};

一旦方法受到保護,它就會被提供給派生類,以便按照自己的意願去做。 using聲明的意圖不是更改繼承的方法訪問,而是避免方法隱藏的問題(如果定義了不同的重載,則X中的公共方法將隱藏在類型Y )。

現在,事實是,由於語言規則,它可以用於更改“已使用”方法的訪問級別,如您的示例所示,但這並沒有真正打開系統中的任何漏洞。 最后,派生類不能做任何比以前更多的事情。

如果實際問題是從設計的角度來看特定用法是否違反封裝(這里的設計是應用程序設計,而不是語言設計),那么很可能是肯定的。 與公開內部數據或方法的方式完全相同。 如果它被設計為受X的初始設計者保護,那么很可能Y實現者不希望它被公開......(或者為同一目的提供委托方法)

沒有。

要使用公共方法,您應該有一個Y的實例,這將不起作用:

int main()
{
    X y1;
    y1.protectedFunction();
}

如果新定義中的Y暴露了一個新接口,那么Y.X仍然受到保護。

在C ++中,即使是私有修飾符也不能保證封裝。 沒有人可以阻止你在腳下射擊自己。

Herb Sutter在他的文章“ 使用和濫用訪問權限 ”中闡述了如何“打破封裝”的不同方式。

這是赫伯文章中的有趣例子。

邪惡的宏觀魔法

#define protected public // illegal
#include "X.h"
//...
X y1;
y1.protectedFunction();

類設計者應該知道聲明一個成員函數或變量(雖然所有變量應該是私有的,真的)作為受保護的大多數與聲明它是公開的(因為你展示它很容易訪問受保護的東西)。 考慮到這一點,在基類中實現這些功能時應注意考慮“意外”使用。 這不是對封裝的違反,因為您可以訪問它並公開它。

受保護只是一種宣傳公開的更復雜的方式!

不,我真的沒有看到問題。

而不是using ,你可以做到這一點:

class X
{
protected:
    void protectedFunction() { cout << "i am protected" ; }
};

class Y : public X
{
public:
    void protectedFunction() { X::protectedFunction(); }
};

任何類都可以接受任何可見的成員,並決定公開公開它。 這樣做可能是糟糕的課堂設計,但它肯定不是語言中的缺陷。 私有或受保護成員的整個要點是,類本身必須決定誰應該訪問該成員。 如果班級決定“我將給全世界訪問”,那么這就是班級的設計方式。

如果我們遵循您的邏輯,那么getter和setter也會違反封裝。 有時它們會這樣做。 但不是因為語言被打破了。 僅僅因為你選擇設計破碎的課程。

通過使成員受到保護,您可以為派生類提供對成員執行任何操作的自由。 他們可以看到它,因此他們可以修改它,或公開公開它。 當您保護成員時,您選擇使這成為可能。 如果你不想那樣,你應該把它變成私人的。

就個人而言,我認為這個問題應該更多地回答為設計問題而不是技術問題。

我會問,“首先,受保護的方法有什么意義?” 它是一個只有子類應該調用的方法,還是一個子類應該覆蓋的方法? 但是,它可能是一種在通用基類中不期望的方法,但可能在子類中預期。 對於基類的客戶端,他們從未知道該受保護的方法。 子類的創建者選擇擴展合同,現在受保護的方法是公開的。 問題確實不應該是C ++允許的,但它適合你的課程,合同和未來的維護者。 當然它可能是一種難聞的氣味,但實際上你需要使其適用於所涉及的用例。

如果確實將受保護的方法設為公開,請確保為維護者正確提供內部文檔,說明為何做出此特定決策的理由。

一般來說,為了安全起見,作為前面提到的貢獻者,您可能希望在子類中使用委托函數(具有不同的名稱)。 因此,不是“get(int)”而是“getAtIndex(int)”或其他東西。 這使您可以更輕松地重構/保護/抽象/記錄將來的文檔。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM