views:

396

answers:

10
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 function of base class. Doesnt this violate the encapsulation principle

is there a specific reason why this is in standard, any uses of this , or is it going to be changed in the new standard, any open issues related to this in standard

+12  A: 

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.

Otávio Décio
He also said that he thought that protected functions were a good idea. The issue here is the use of "using" (which I would suggest is bad) rather than the use of "protected".
anon
No. The problem with protected is that it does not really provide any protection (that was Bjoarne's argument). To get access to the method all you need to do is inherit from the class thus breaking encapsulation. In affect protected is no safer than using public.
Martin York
@Martin, The book says protected functions: good, protected data: bad. Have you actually read it?
anon
@Neil: Yes I have, and yes you are correct (in your second post which is orthogonal to your first). __BECAUSE__ The same rules that apply to public interface also apply to protected interface (methods exposed/data hidden); and this is because 'protected access' provides no more protection than a 'public 'access (because it is easy to subvert at the language level purely by inheriting from it).
Martin York
My first comment (not post) said "using::sonefunc" == "bad". I don't see how this is orthogonol to protected/private/public.
anon
using::sonefunc" == "bad" -- is orthogonal to -- "functions: good, protected data: bad". Both of course are true. But address very different issues. Its not that I don't agree that using::XX can be bad, I disagree in your interpration of Bjarne's meaning over the protected access, and from my reading of the quote above he regrets the whole concept of 'protected access'.
Martin York
@Martin "orthogonal" != "different"
anon
@Neil: You must need coffie badly if you want argue over word symantics with me rather than language issues. Orthogonal: "At right angles". Your two arguments though they are related (ie they have a meeting point) they are different arguments (thus diverge at an angle (maybe not at 90 degrees)). ;-) I believe (having had a good clasical education in the UK) my usage here is more than valid (though my spelling is often off. I blame dyslexia).
Martin York
@Martin Precisely. To have a combined concept of a right-angle, the two sub concepts must meet. And "using" and "protected" don't - they just differ. But perhaps this is taking the SO comment mechanism far beyond what it was intended for. And and in any case we will obviously never agree.
anon
ok guys...chill
Yogesh Arora
@Neil: Though because you spent the last three posts argue about symantics; one can infer that you have no counter argument to my second comment. (Bjarne was talking about protected being the mistake).
Martin York
@Yogesh You are right - chilling(on).
anon
@Yogesh Though no doubt people will now criticise me for not impelmenting the member function hassle.chillDude();
anon
+16  A: 

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.

Mykola Golubyev
+9  A: 

I think it was Stroustrup himself that said the encapsulation and data integrity features built into C++ are designed to keep honest people honest, not to stop criminals.

Andrew Noyes
I love some of the answers in the C++FAQ to these type of questions. 'How can I prohibit others from...' - write a comment saying so, 'and how do I actually block them from doing...' - write a comment stating that they will be fired if they do. 'But what if I really, really want to impede...' - fire the guy.
David Rodríguez - dribeas
+3  A: 

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

Hexagon
-1: The code in question doesn't call the protected method from the context of the derived class. The protected method is called from the scope of main(). If you remove the 'using' declarator, the code no longer compiles.
John Dibling
@John, This is obvious! This is just a shortcut, instead of doing the "trampoline" function yourself. It doesn't increase nor does it decrease the protection level of the function.
Hexagon
@John Dibling: Which means that the program writer exposed the function deliberately. It would have been almost as easy to slap a public wrapper function about it. I see no reason for a downvote here.
David Thornley
@John, I'm saying exactly what Mykola is saying, just two minutes too late, and without a code example...
Hexagon
I downvoted because Hexagon seemed to be saying that you could have called the protected method directly from outside the class. Which is obviously wrong at a very basic level. If that's not what you were saying, then I'll remove the d/v.
John Dibling
@John, Exactly so. I was implying that you could directly call the function from the derived class, so you aren't exposing anything that can't be exposed anyway. I will correct the answer to reflect that more clearly, although this is largely a moot point. Mykola's answer is better...
Hexagon
Un-downvoted. My mistake.
John Dibling
+1  A: 

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!

Francis Boivin
More like a way of making it possible to be declared public, I'd say.
David Thornley
+1  A: 

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)

David Rodríguez - dribeas
+2  A: 

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.

OscarRyz
+1  A: 

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();
Sergey Teplyakov
That's undefined behavior, partly because it breaks the one definition rule. Even if redefining "protected" was legal, you couldn't count on class members being in the same order.
David Thornley
Yes, I know about undefined behavior. I want to show that THIS is trick, that "break encapsulatino", but wrapping protected fuction is not.
Sergey Teplyakov
+1  A: 

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.

jalf
+1  A: 

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.

Andrew Mellinger