8

The following code produces a compiler error:

'BaseTest::_protMember' : cannot access protected member declared in class 'BaseTest'

Why can't I access the member variable _protMember in my class SubTest even though it is protected?

class BaseTest
{
public:
    BaseTest(){};

    BaseTest(int prot)
    {
        _protMember = prot;
    };

protected:
    int _protMember;
};

class SubTest : public BaseTest
{
    // followup question
    SubTest(const SubTest &subTest)
    {
        _protMember = subTest._protMember; // this line compiles without error
    };

    SubTest(const BaseTest &baseTest)
    {
        _protMember = baseTest._protMember; // this line produces the error
    };
};

Followup question:

Why is it, that in the added copy constructor I can access protected members of another instance?

TooTone
  • 7,129
  • 5
  • 34
  • 60
Ronald McBean
  • 1,417
  • 2
  • 14
  • 27

3 Answers3

13

You can only access protected members from your own base class instance... not one provided to you as a parameter. It's all about OO encapsulation really. Without this restriction, the object under construction could invalidate invariants of the baseTest& parameter.

Put another way, your SubTest may decide on a use for a protected member that conflicts with the usage made of the same member by another BaseTest-derived class (say SubTest2 : BaseTest). If your SubTest code was allowed to fiddle with the other object's data, it could invalidate the invariants in a SubTest2 object, or get some values out that were - in the intended encapsulation - only meant to be exposed to SubTest2 and (optionally - see below) SubTest2 derivatives.

Followup question: Why is it, that in the added copy constructor I can access protected members of another instance?

SubTest(const SubTest& x);  // can access x._protMember
SubTest(const BaseTest& x);  // cannot access x._protMember

The same insights above explain why this is allowed: the copy constructor gets a SubTest& rather than just any old object derived from BaseTest, and this constructor is clearly within the SubTest abstraction. The SubTest coder is assumed to be conversant with the intended design/encapsulation SubTest provides, and the copy constructor is given access to bypass and enforce post-conditions/invariants on the other SubTest& object too. (You are copying from an object that might itself have been copy-constructed by the very same function, so protecting it when on the "*this" side but not the parameter-by-ref side isn't much protection at all, even ignoring all the sound reasons you may want/need that access).

It is possible that a SubTest-derived object will be accidentally passed to the SubTest copy constructor ("slicing"), but even for that scenario the SubTest& class can control whether the further-derived object could have been doing anything unexpected with _protMember - adding a private using BaseTest::_protMember; statement if it wants to "finalise" access to _protMember and forbid any derived classes from using it.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • Thanks for your answer. Could you have a look at my followup question I added (with a function that _can_ access protected members of another instance. – Ronald McBean Jul 18 '13 at 07:40
  • @RonaldMcBean: I've added to my answer addressing that. ("that can access protected members of another instance" - but not a `BaseTest`-but-not-`SubTest`-derived instance - there's the rub). – Tony Delroy Jul 18 '13 at 08:40
  • 2
    This is a great answer. I came across this issue a few years ago and it took me a long time to work out **why** the compiler behaved that way. What I realized is that the designers of C++ have done a great job in understanding the subtleties of where the responsibilities lie in object orientation. – TooTone Jul 18 '13 at 09:36
6

You can access protected members only in the class instance. That is :

class SubTest : public BaseTest
{
    SubTest(const BaseTest &baseTest)
    {
        _protMember = baseTest._protMember;
     // ^^^^^^^^^^^ Is good because you are in the instance of its class
        _protMember = baseTest._protMember;
     //               ^^^^^^^^^^^^^^^^^^^^^ Produce error because you are not in the baseTest instance.              
    };

    // followup question
    SubTest(const SubTest &subTest)
    {
        _protMember = subTest._protMember;
      // Compile because access modifiers work on class level, and not on object level.
    };
};

EDIT for the followup :

The access modifiers work on class level, and not on object level.

That is, two objects of the same class can access each others private members.

This is my source : Why can I access private variables in the copy constructor?

Community
  • 1
  • 1
Pierre Fourgeaud
  • 14,290
  • 1
  • 38
  • 62
0

By defining _protMember as protected you allow objects of derived classes to access their own _protMember. This does not mean all objects of derived classes can access _protMember of other objects.

Kolyunya
  • 5,973
  • 7
  • 46
  • 81