简体   繁体   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();
}

This way I am able to expose one of the functions of the base class. 这样我就可以公开基类的一个功能。

  1. Doesn't this violate the encapsulation principle? 这不违反封装原则吗?
  2. Is there a specific reason as to why this is in standard? 是否有一个特定的原因,为什么这是标准的?
  3. Is there any uses of this, or is it going to be changed in the new standard? 是否有任何用途,或者是否会在新标准中进行更改?
  4. Are there any open issues related to this in the standard? 标准中是否存在与此相关的未解决问题?

You did it by yourself. 你是自己做的。
You could write 你可以写

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

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

I don't see any reason to worry about it. 我认为没有理由担心它。
Protected functions are pieces of reusable logic in the inheritance tree. 受保护的函数是继承树中可重用逻辑的一部分。 You can hide them if there is some internal logic or restriction or like in your case you can expose it if you are sure that this won't harm anyone. 你可以隐藏它们,如果有一些内部逻辑或限制,或者像你的情况那样你可以暴露它,如果你确定这不会伤害任何人。

Yes it does and that's why protected has received a fair share of criticism. 是的,这就是为什么受保护已经受到了公平的批评。

Bjarne Stroustrup, the creator of C++, regrets this in his excellent book The Design and Evolution of C++: C ++的创建者Bjarne Stroustrup在他的优秀着作“C ++的设计和演变”中对此感到遗憾:

One of my concerns about protected is exactly that it makes it too easy to use a common base the way one might sloppily have used global data....In retrospect, I think that protected is a case where "good arguments" and fashion overcame my better judgement and my rules of thumb for accepting new features. 我对受保护的一个担忧正是因为它太容易使用一个共同的基础,就像人们可能已经习惯使用全局数据一样....回想起来,我认为受保护是一个“好的论据”和时尚克服的情况我更好的判断力和接受新功能的经验法则。

我认为正是Stroustrup本人说C ++中内置的封装和数据完整性功能旨在让诚实的人保持诚实,而不是阻止犯罪分子。

No. protectedFunction() is protected. 编号protectedFunction()受保护。 You are free to call it from derived classes, so you could have called it directly from a public member of Y, and call this public member from main(). 您可以从派生类中自由调用它,因此您可以直接从Y的公共成员调用它,并从main()调用此公共成员。

If you could have done that with a private method, there would have been a problem... (EDITED to be a bit clearer). 如果您可以使用私有方法完成此操作,则会出现问题...(编辑更清楚一点)。

From the language point of view, that is not more of a violation of encapsulation than creating a delegate method in the derived object: 从语言的角度来看,与在派生对象中创建委托方法相比,这不仅仅是对封装的违反:

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

Once a method is protected, it is offered to the deriving classes to do with it as they wish. 一旦方法受到保护,它就会被提供给派生类,以便按照自己的意愿去做。 The intention for the using declaration was not changing the inherited methods access but rather avoiding problems with method hidding (where a public method in X would be hidden in type Y if a different overload is defined). using声明的意图不是更改继承的方法访问,而是避免方法隐藏的问题(如果定义了不同的重载,则X中的公共方法将隐藏在类型Y )。

Now, it is a fact that due to the language rules it can be used to change the access level for 'used' methods as in your example, but that does not really open any hole in the system. 现在,事实是,由于语言规则,它可以用于更改“已使用”方法的访问级别,如您的示例所示,但这并没有真正打开系统中的任何漏洞。 At the end, derived classes cannot do anything more than what they could do before. 最后,派生类不能做任何比以前更多的事情。

If the actual question is whether the particular usage is a violation of encapsulation from a design point of view (where design here is application design, not language design), then most probably yes. 如果实际问题是从设计的角度来看特定用法是否违反封装(这里的设计是应用程序设计,而不是语言设计),那么很可能是肯定的。 In exactly the same way that making internal data or methods public. 与公开内部数据或方法的方式完全相同。 If it was designed to be protected by the initial designer of X , then chances are that Y implementor did not want it to be public... (or offering a delegating method for the same purpose) 如果它被设计为受X的初始设计者保护,那么很可能Y实现者不希望它被公开......(或者为同一目的提供委托方法)

No. 没有。

To use the public method you should have an instance of Y this won't work: 要使用公共方法,您应该有一个Y的实例,这将不起作用:

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

If Y in its new definition exposes a new interface it's up the Y. X is still protected. 如果新定义中的Y暴露了一个新接口,那么Y.X仍然受到保护。

In C++ even private modifier doesn't guarantees encapsulation. 在C ++中,即使是私有修饰符也不能保证封装。 No one can stop you from shooting yourself in your foot. 没有人可以阻止你在脚下射击自己。

Herb Sutter in his article " Uses and Abuses of Access Rights " demostrates different ways how you can "break encapsulation". Herb Sutter在他的文章“ 使用和滥用访问权限 ”中阐述了如何“打破封装”的不同方式。

Here funny example from Herb's article. 这是赫伯文章中的有趣例子。

Evil macro magic 邪恶的宏观魔法

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

Class designer should know that declaring a member function or variable (though all variables should be private, really) as protected is mostly the same as declaring it public (as you showed it's easy to get access to protected stuff). 类设计者应该知道声明一个成员函数或变量(虽然所有变量应该是私有的,真的)作为受保护的大多数与声明它是公开的(因为你展示它很容易访问受保护的东西)。 With that in mind, care as to be taken when implementing those functions in the base class to account for "unexpected" use. 考虑到这一点,在基类中实现这些功能时应注意考虑“意外”使用。 It's not a violation of encapsulation because you can access it and expose it. 这不是对封装的违反,因为您可以访问它并公开它。

protected is just a more complicated way of declaring something public! 受保护只是一种宣传公开的更复杂的方式!

No, I don't really see the problem. 不,我真的没有看到问题。

Instead of using , you could have done this: 而不是using ,你可以做到这一点:

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

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

Any class can take any member that is visible to it, and decide to expose it publicly. 任何类都可以接受任何可见的成员,并决定公开公开它。 It may be bad class design to do so, but it is certainly not a flaw in the language. 这样做可能是糟糕的课堂设计,但它肯定不是语言中的缺陷。 The entire point in private or protected members is that the class itself must decide who should get access to the member. 私有或受保护成员的整个要点是,类本身必须决定谁应该访问该成员。 And if the class decides "I'm going to give the whole world access", then that is how the class is designed. 如果班级决定“我将给全世界访问”,那么这就是班级的设计方式。

If we follow your logic through, then getter and setters violate encapsulation too. 如果我们遵循您的逻辑,那么getter和setter也会违反封装。 And sometimes they do. 有时它们会这样做。 But not because the language is broken. 但不是因为语言被打破了。 Simply because you're choosing to design broken classes. 仅仅因为你选择设计破碎的课程。

By making a member protected, you give derived classes the freedom to do anyting they like with the member. 通过使成员受到保护,您可以为派生类提供对成员执行任何操作的自由。 They can see it, so they can modify it, or expose it publicly. 他们可以看到它,因此他们可以修改它,或公开公开它。 You chose to make this possible when you made the member protected. 当您保护成员时,您选择使这成为可能。 If you didn't want that, you should've made it private. 如果你不想那样,你应该把它变成私人的。

Personally I think this question should be answered as more of a design question rather than a technology question. 就个人而言,我认为这个问题应该更多地回答为设计问题而不是技术问题。

I would ask, "What was the point of the protected method in the first place?" 我会问,“首先,受保护的方法有什么意义?” Was it a method that only subclasses should call, or is it a method that subclasses should override? 它是一个只有子类应该调用的方法,还是一个子类应该覆盖的方法? However, it may be a method that is not expect in a generic base class, but maybe expected in a subclass. 但是,它可能是一种在通用基类中不期望的方法,但可能在子类中预期。 To the client of the base class they never knew about that protected method. 对于基类的客户端,他们从未知道该受保护的方法。 The creator of the subclass chose to expand the contract and now that protected method is public. 子类的创建者选择扩展合同,现在受保护的方法是公开的。 The question really should be not does C++ allow it, but is it right for you class, contract and future maintainers. 问题确实不应该是C ++允许的,但它适合你的课程,合同和未来的维护者。 Sure it might be a bad smell, but really you need to make it right for the use case involved. 当然它可能是一种难闻的气味,但实际上你需要使其适用于所涉及的用例。

If you do make the protected method public then make sure you properly provide internal documentation for the maintainer explaining the rationale of why this particular decision is made. 如果确实将受保护的方法设为公开,请确保为维护者正确提供内部文档,说明为何做出此特定决策的理由。

In general though, for safety sake as a previous contributor mentioned, you probably want to use a delegate function (with a different name) in the subclass. 一般来说,为了安全起见,作为前面提到的贡献者,您可能希望在子类中使用委托函数(具有不同的名称)。 So instead of "get(int)" you might have "getAtIndex(int)" or something. 因此,不是“get(int)”而是“getAtIndex(int)”或其他东西。 This allows you to more easily refactor/protect/abstract/document that in the future. 这使您可以更轻松地重构/保护/抽象/记录将来的文档。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM