Question

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?

Was it helpful?

Solution

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;
}

OTHER TIPS

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)

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 ) {}
};

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;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top