11

I am confused: I thought protected data was read/writable by the children of a given class in C++.

The below snippet fails to compile in MS Compiler

class A
{
protected:
  int data;
};

class B : public A
{
  public:

  B(A &a)
  {
    data = a.data;
  }
};

int main()
{
  A a;
  B b = a;
  return 0;
}

Error Message:

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

demoFail.cpp
demoFail.cpp(12) : error C2248: 'A::data' : cannot access protected member declared in class 'A'
        demoFail.cpp(4) : see declaration of 'A::data'
        demoFail.cpp(2) : see declaration of 'A'

What am I doing wrong?

Paul Nathan
  • 39,638
  • 28
  • 112
  • 212

4 Answers4

10

According to TC++PL, pg 404:

A derived class can access a base class’ protected members only for objects of its own type.... This prevents subtle errors that would otherwise occur when one derived class corrupts data belonging to other derived classes.

Of course, here's an easy way to fix this for your case:

class A
{
protected:
    int data;
};

class B : public A
{
public:
    B(const A &a)
        : A(a)
    {
    }
};

int main()
{
    A a;
    B b = a;
    return 0;
}
rlbond
  • 65,341
  • 56
  • 178
  • 228
  • Umph. To be precise, this case is a dummy case only to demonstrate the problem. I actually wanted to do some fairly intensive reading of the data being passed in. – Paul Nathan Sep 12 '09 at 07:23
  • In any case you can muck around only with the protected data in the A part of this or another B object. If you have an A instance or a C instance that also derives from A, B has no special rights to those As. If you can't take this advice (make this A part of this B by copying it to be the base part of this B, which you do have access to), then you might have a design problem which might require the bigger picture to answer. – UncleBens Sep 12 '09 at 08:31
  • @rlbond: Coding after bedtime strikes again. This did solve my problem. Thanks. :) – Paul Nathan Sep 12 '09 at 20:32
2

The C++ Standard says about protected non-static members at 11.5/1

When a friend or a member function of a derived class references a protected nonstatic member function or protected nonstatic data member of a base class, an access check applies in addition to those described earlier in clause 11. Except when forming a pointer to member (5.3.1), the access must be through a pointer to, reference to, or object of the derived class itself (or any class derived from that class) (5.2.5). If the access is to form a pointer to member, the nested-name-specifier shall name the derived class (or any class derived from that class).

In addition to fixing things mentioned earlier by others (constructor of B is private), i think rlbond's way will do it fine. However, a direct consequence of the above paragraph of the Standard is that the following is possible using a member pointer, which arguably is a hole in the type system, of course

class B : public A {
public:
  B(A &a){
    int A::*dataptr = &B::data;
    data = a.*dataptr;
  }
};

Of course, this code is not recommended to do, but shows that you can access it, if you really need to (I've seen this way being used for printing out a std::stack, std::queue, std::priority_queue by accessing its protected container member c)

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • hi Johannes Schaub - litb can you please show me how to access protected member c in std::stack or std::queue i have problem with accessing it it gave me an error C2248: 'std::stack<_Ty>::c' : cannot access protected member declared in class 'std::stack<_Ty>' thanks –  Feb 04 '11 at 05:38
1

You just shouldn't copy an A object in a B constructor. The intention is to leave the initialization of A's members to it's own constructor:

struct A { 
  A( const A& a ): data( a.data ) {}
  protected: int data; 
};

struct B : public A {
  B( const A& a ): A( a ) {}
};
xtofl
  • 40,723
  • 12
  • 105
  • 192
0

The constructor of B is private. If you do not specify anything, in a class, the default modifier is private (for structs it is public). So in this example the problem is that you cannot construct B. When you add public to constructor B anoter problem arises:

B has the right to modify the part of A it derives from but not another A like in this case.

You could do following:

class A
{
public:
  A()
      : data(0)
  {
  }
  A(A &a)
  {
    data = a.data;
  }
protected:
  int data;
};

class B : public A
{
public:
  B(A &a)
      : A(a)
  {
  }
};

int main()
{
  A a;
  B b = a;
  return 0;
}
jdehaan
  • 19,700
  • 6
  • 57
  • 97