繁体   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