89

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.

1
  • 4
    Check out gotw.ca/gotw/076.htm (Note: don't use that stuff in production code).
    – Brian
    Commented Jul 14, 2010 at 17:32

8 Answers 8

67

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.

9
  • 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
    Commented Feb 5, 2012 at 3: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:stackoverflow.com/questions/9139824/… Commented Feb 6, 2012 at 3:52
  • 3
    @SLaks What do you mean by "Changing the constructor to take a Derived instance will also solve the problem." ? Commented Apr 3, 2013 at 10:10
  • 2
    @SLaks but why instance of Base class have access to pivate members of other instance of this Base class?
    – user3191398
    Commented Aug 3, 2016 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? Commented Feb 2, 2018 at 12:25
15

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.

1
  • Seems like a C++ language mistake to have to say this-> for an accessible member with no name hiding. Java got it right!\? Commented Jan 10 at 22:08
9

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;
    }
};
1
  • 2
    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
    Commented Jul 14, 2010 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)

1
  • 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
    Commented Jun 1, 2013 at 3: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;
    }
};
3
  • 2
    If the dynamic type of that is not (cv) Derived, the behavior is undefined.
    – xskxzr
    Commented Feb 15, 2019 at 4:57
  • But, for this case, b is alway a data member of base class!
    – Martin.Bof
    Commented Mar 7, 2019 at 20:52
  • Or better, you can use: b += static_cast<const Derived*>(that)->Base::b;
    – Martin.Bof
    Commented Mar 7, 2019 at 21:13
2

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
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
    Commented Jan 14, 2020 at 16:13
1
class Derived : public Base
{
  protected:
    int d;
  public:
    void DoSomething()
    {
      b+=this->b;
      d=0;
    }
};

//this will work
-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;
    }
};
4
  • 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
    Commented Oct 25, 2016 at 14:49
  • 4
    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. Commented Jan 11, 2018 at 22:00
  • This works, at least in Visual Studio 2019. Commented Apr 25, 2021 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
    Commented Mar 28, 2022 at 11:09

Not the answer you're looking for? Browse other questions tagged or ask your own question.