Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why protected superclass member cannot be accessed in a subclass function when passed as an argument?

I get a compile error, which I'm slightly confused about. This is on VS2003.

error C2248: 'A::y' : cannot access protected member declared in class 'A'

class A
{
public:
  A() : x(0), y(0) {}
protected:
  int x;
  int y;
};

class B : public A
{
public:
  B() : A(), z(0) {}
  B(const A& item) : A(), z(1) { x = item.y;}
private:
  int z;
};

The problem is with x = item.y;

The access is specified as protected. Why doesn't the constructor of class B have access to A::y?

like image 460
Chris Bednarski Avatar asked Apr 01 '10 03:04

Chris Bednarski


People also ask

What happens when a subclass inherits the protected superclass?

A subclass inherits all the members (fields, methods, and nested classes) from its superclass. Constructors are not members, so they are not inherited by subclasses, but the constructor of the superclass can be invoked from the subclass.

Can subclass access protected members?

We can access protected members of a class in its subclass if both are present in the same package.

Can we access protected member outside the class?

Protected members in a class are similar to private members as they cannot be accessed from outside the class. But they can be accessed by derived classes or child classes while private members cannot.

How are protected members of base class accessed in the derived class when inherited privately in C Plus Plus?

If a class is derived privately from a base class, all protected base class members become private members of the derived class. Class A contains one protected data member, an integer i . Because B derives from A , the members of B have access to the protected member of A .


2 Answers

It's because of this:

class base_class
{
protected:
    virtual void foo() { std::cout << "base::foo()" << std::endl; }
};

class A : public base_class
{
protected:
    virtual void foo() { std::cout << "A::foo()" << std::endl; }
};

class B : public base_class
{
protected:
    virtual void foo() { std::cout << "B::foo()" << std::endl; }

public:
    void bar(base_class *b) { b->foo(); }
};

If that were legal, you could do this:

A a;
B b;
b.bar(&a);

And you'd be calling a protected member of A from B, which isn't allowed.

like image 179
Dean Harding Avatar answered Oct 25 '22 07:10

Dean Harding


The other answers explain the reasoning behind preventing your B object from accessing the protected parts of A in your example, even though B 'is-a' A. Of course, the easiest way to fix this problem is to make the parts of A you want access topublic` or have publicly accessible accessor methods.

However you might decide that's inappropriate (or you might not have control over the definition of A). Here are some suggestions to let you work around the problem, in increasing order of subverting A's access control. Note that all of these workarounds assume that class A is copy-constructable.

In the first case, you simply use the copy constructor for A to set up an initial state for that part of the B object, then fix it up afterward:

class B1 : public A
{
public:
  B1() : A(), z(0) {}
  B1(const A& item) : A(item), z(1) {
    // fix up the A sub-object that was copy constructed 
    //  not quite the way we wanted
    x = y;
    y = 0;
  }
private:
  int z;
};

I find that incredibly confusing and probably very error prone (assuming that we want the A sub-object in the B object to be different than the A object being passed to the constructor - an unusual situation, but it's what was given in the problem). However, the fact that it can be done gives some justification for the more subversive examples that follow...

The next example creates a temporary B object that has an exact duplicate of the A object we want access to. We can then use the temporary B object to get to the items that were protected:

class B2 : public A
{
public:
  B2() : A(), z(0) {}
  B2(const A& item) : A(), z(1) {
    // create a special-use B2  object that can get to the 
    //  parts of the A object we want access to
    B2 tmp( item, internal_use_only);

    x = tmp.y;  // OK since tmp is of type B
  }

private:
  int z;

  // create a type that only B2 can use as a 
  //    'marker' to call a special constructor 
  //    whose only purpose in life is to create
  //    a B object with an exact copy of another
  //    A sub-object in it
  enum internal_use {
    internal_use_only
  };
  B2( const A& item, internal_use marker) : A(item), z(0) {};
};

I find that solution to be a bit less confusing than the first, but it's still confusing (in my opinion). Having a bastard version of of B object just to get to the parts of the A object we want is odd.

We can do something about that by creating a special proxy for A objects that gives the access we want. Note that this is the 'most subversive' workaround because it's something that any class could do to get to protected parts of A, even if they aren't sub-classes of A themselves. In the case of the B class, there's some legitimacy to getting to the protected parts of A objects, since B is-a A, and as we've already seen there are workarounds that let us get access that use only rights that class B already has, so I consider this a cleaner version of those workarounds in class B's case.

class B3 : public A
{
public:
  B3() : A(), z(0) {}
  B3(const A& item) : A(), z(1) { 
    // a special proxy for A objects that lets us
    //  get to the parts of A we're interested in
    A_proxy tmp( item);
    x = tmp.get_y();
  }

private:
  int z;

    class A_proxy : public A
    {
    public:
        A_proxy( const A& other) : A(other) {};
        int get_x() {return x;};
        int get_y() {return y;};
    };

};
like image 44
Michael Burr Avatar answered Oct 25 '22 07:10

Michael Burr