简体   繁体   中英

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++:

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. 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().

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).

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)

No.

To use the public method you should have an instance of Y this won't work:

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.

In C++ even private modifier doesn't guarantees encapsulation. 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".

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:

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. 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. 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. This allows you to more easily refactor/protect/abstract/document that in the future.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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