84

I ran into an error yesterday and, while it's easy to get around, I wanted to make sure that I'm understanding C++ right.

I have a base class with a protected member:

class Base
{
  protected:
    int b;
  public:
    void DoSomething(const Base& that)
    {
      b+=that.b;
    }
};

This compiles and works just fine. Now I extend Base but still want to use b:

class Derived : public Base
{
  protected:
    int d;
  public:
    void DoSomething(const Base& that)
    {
      b+=that.b;
      d=0;
    }
};

Note that in this case DoSomething is still taking a reference to a Base, not Derived. I would expect that I can still have access to that.b inside of Derived, but I get a cannot access protected member error (MSVC 8.0 - haven't tried gcc yet).

Obviously, adding a public getter on b solved the problem, but I was wondering why I couldn't have access directly to b. I though that when you use public inheritance the protected variables are still visible to the derived class.

miked
  • 3,458
  • 1
  • 22
  • 25
  • 3
    Check out http://www.gotw.ca/gotw/076.htm (Note: don't use that stuff in production code). – Brian Jul 14 '10 at 17:32

8 Answers8

65

A class can only access protected members of instances of this class or a derived class. It cannot access protected members of instances of a parent class or cousin class.

In your case, the Derived class can only access the b protected member of Derived instances, not that of Base instances.

Changing the constructor to take a Derived instance will solve the problem.

Géry Ogam
  • 6,336
  • 4
  • 38
  • 67
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Do you mean to say here that we can access the protected members from our own objects not from base class's objects? If yes, then why is so? – Aquarius_Girl Feb 04 '12 at 11:59
  • 1
    @AnishaKaul: You can only access your base class' protected members in an instance of your type, not a cousin type. For example, `Button` cannot access a protected property from `Control` on a `TextBox`. – SLaks Feb 05 '12 at 03:07
  • 1
    `You can only access your base class' protected members in an instance of your type, not a cousin type` You have again written the same statement which you wrote above. Please have a look here:http://stackoverflow.com/questions/9139824/how-to-access-protected-members-in-a-derived-class – Aquarius_Girl Feb 06 '12 at 03:52
  • 3
    @SLaks What do you mean by "Changing the constructor to take a Derived instance will also solve the problem." ? – Mickael Bergeron Néron Apr 03 '13 at 10:10
  • 1
    @MickaelBergeronNéron: Because then you'll be accessing a protected member on your own type. – SLaks Apr 03 '13 at 13:30
  • It's not a constructor (if you mean changing `void Derived::DoSomething(const Base& that)` to `void Derived::DoSomething(const Derived& that)`). – MKPS Dec 22 '14 at 19:58
  • 2
    @SLaks but why instance of Base class have access to pivate members of other instance of this Base class? –  Aug 03 '16 at 16:34
  • 2
    How about an accessor method in base class, virtual and protected, that you can call from the derived class passing a reference to another instance of the base class or a derived class? – turbopapero Feb 02 '18 at 12:25
  • The lucidity of your answer is awesome. Suggestion: change the wording of the last line to "Changing the `DoSomething` prototype to ..." – Ryan Dsouza Oct 11 '20 at 19:11
12

protected members can be accessed:

  • through this pointer
  • or to the same type protected members even if declared in base
  • or from friend classes, functions

To solve your case you can use one of last two options.

Accept Derived in Derived::DoSomething or declare Derived friend to Base:

class Derived;

class Base
{
  friend class Derived;
  protected:
    int b;
  public:
    void DoSomething(const Base& that)
    {
      b+=that.b;
    }
};

class Derived : public Base
{
  protected:
    int d;
  public:
    void DoSomething(const Base& that)
    {
      b+=that.b;
      d=0;
    }
};

You may also consider public getters in some cases.

Sergei Krivonos
  • 4,217
  • 3
  • 39
  • 54
8

As mentioned, it's just the way the language works.

Another solution is to exploit the inheritance and pass to the parent method:

class Derived : public Base
{
  protected:
    int d;
  public:
    void DoSomething(const Base& that)
    {
      Base::DoSomething(that);
      d=0;
    }
};
sje397
  • 41,293
  • 8
  • 87
  • 103
  • 1
    I gave a bad example in the question, but I cannot call Base::DoSomething because the DoSomething actually goes about doing it's thing differently when it comes into a Derived rather than a Base. – miked Jul 14 '10 at 15:42
4

You have access to the protected members of Derived, but not those of Base (even if the only reason it's a protected member of Derived is because it's inherited from Base)

James Curran
  • 101,701
  • 37
  • 181
  • 258
  • 1
    This doesn't work. Consider "You have access to the `private` members of `Derived`." and the implications for inherited `private` members of `Base`. – Ben Voigt Jun 01 '13 at 03:22
3

You can try with static_cast< const Derived*>(pBase)->Base::protected_member ...

class Base
{
  protected:
    int b;

  public:
    ...
};

class Derived : public Base
{
  protected:
    int d;

  public:
    void DoSomething(const Base& that)
    {
      b += static_cast<const Derived*>(&that)->Base::b;
      d=0;
    }
    void DoSomething(const Base* that)
    {
      b += static_cast<const Derived*>(that)->Base::b;
      d=0;
    }
};
Martin.Bof
  • 56
  • 4
1
class Derived : public Base
{
  protected:
    int d;
  public:
    void DoSomething()
    {
      b+=this->b;
      d=0;
    }
};

//this will work
1

Following the hack for stl I wrote a small code which seems to solve the problem of accessing the protected members in derived class

#include <iostream>

class B
{
protected:
    int a;
public:
    void dosmth()
    {
        a = 4;
    }

    void print() {std::cout<<"a="<<a<<std::endl;}
};

class D: private B
{
public:
    void dosmth(B &b)
    {
        b.*&D::a = 5;
    }
};

int main(int argc, const char * argv[]) {

    B b;
    D d;
    b.dosmth();
    b.print();
    d.dosmth(b);
    b.print();

    return 0;
}

Prints

a=4
a=5
Stiv Zhops
  • 11
  • 1
  • It turns out that my example is nearly the same as one posted above. I also wandered that it works. From my opinion it to casting to a derived type, but I'm not sure. – Stiv Zhops Jan 14 '20 at 16:13
-2

Use this pointer to access protected members

class Derived : public Base
{
  protected:
    int d;
  public:
    void DoSomething(const Base& that)
    {
      this->b+=that.b;
      d=0;
    }
};
Joe Kennedy
  • 9,365
  • 7
  • 41
  • 55
  • 1
    This answer is wrong. The derived class cannot access "b" of the base class as it is declared as protected (this is what the user asked in the first place). This code will generate a compiler error. – tantuni Oct 25 '16 at 14:49
  • 2
    What a non-answer. It's the `b` of `that` that is the problem. And adding `this->` is not only unrelated but also a complete no-op because it's implied if omitted. I wish people would know a tiny bit about a language and test any code they write before posting it as an answer. – underscore_d Jan 11 '18 at 22:00
  • This works, at least in Visual Studio 2019. – Tomasz Gawel Apr 25 '21 at 19:35
  • Best and simplest answer. Works better than everything above. I only wonder why i need "this" to access the protected members of a base class? – timoxd7 Mar 28 '22 at 11:09