3

Consider the following:

#include <iostream>

class Base {
    public:

        void go(){this->doSomething();}

    protected:
        virtual void doSomething(){std::cout << "base";}
};

class DerivedA : public Base {
    protected:
        void doSomething() override {std::cout << "a";}
};

class DerivedB : public Base {
    public:
        Base * basePtr;

        DerivedB()
          :basePtr(new DerivedA())
        {}

    protected:
        void doSomething() override {basePtr->doSomething();} // wont compile
};

int main(int , char *[])
{
   DerivedB b;
   b.go();
}

doSomething() in the DerivedB subclass will not compile, but I do not understand why this behavior exists! I am trying to access a virtual protected member function of my base class, which I would have thought would be allowed.

http://en.cppreference.com/w/cpp/language/access

In the section on protected member access, it says

"A protected member of a class Base can only be accessed 1) by the members and friends of Base 2) by the members and friends (until C++17) of any class derived from Base, but only when operating on an object of a type that is derived from Base (including this)"

According to point 2, if I cast down to the subclass (DerivedA), this would be allowed but I would then be in conflict with the condition that I am accessing a protected member function of a different class (which is not a base class, and would also not compile). Worse, if I knew the sub class type of the derived object, I could still not access it even if I cast to its common base.

Why is this behavior enforced? I assume it is probably going to be a side effect of allowing multiple inheritance etc but I can't think of exactly what it would be. It's annoying because now I have to make a public interface for something which is and should only be used by base or derived classes, which goes against the point of inheritance and access modifiers.

  • 1
    What exactly are you trying to achieve with the Base* basePtr in DerivedB? – Scrontch Mar 31 '17 at 10:21
2

I am trying to access a virtual protected member function of my base class

Yes, but you are trying to do this via another object basePtr, not this object. And that other object is a Base. You somehow mix up classes (types) with objects (instances) of that class. You shouldn't be able to call a protected member function of a Base object when you're not 'in' that same object. And you aren't. The fact that you are executing code inside your derived class doesn't matter here. The access level is not being checked against the instance this of your derived class, but against the instance basePtr you want to access.

And it's fine the way it is. Designers of class Base don't want people to call doSomething on objects of class Base. No matter from where! That's what the word protected says. They are however fine by having doSomething be called from the implementation of instances that are (in the the sense of the is-a-relationship of inheritance) Bases, that means from instances of derived classes.

  • 1
    Mixing up classes and instances is what I have accepted the answer for. The use case was a base class which allows derived classes to add extra actions to a context menu. One of the derived classes is a sort of "group type", and I wanted to be able to call the virtual protected member function which allows each derived class to fill in their specialized bits from the base class for each child item, to append to a sub menu. Its far from the end of the world that this is now a public function, but it is something which is still only used internally by classes which derive the base. – Andy Forrest Mar 31 '17 at 10:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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