1

I always thought that I understood inheritance, but obviously I don't. I would like to call a protected member function of another instance of the same parent class from a child class like in the following example code:

#include <iostream>

class Parent {
protected:
  void doStuff(){
    std::cout << 5 << std::endl;
  }
};

class Child : public Parent {
public:
  void pubfunc(Parent* p){
    p->doStuff();
  }
};

int main(){
  Child* c = new Child();
  Parent* p = new Parent();
  c->pubfunc(p);
  return 0;
}

However, compilation of this code fails with:

In member function ‘void Child::pubfunc(Parent*)’:
error: ‘void Parent::doStuff()’ is protected
error: within this context

I wouldn't want to make the Child class a friend of the Parent class to avoid forward declarations and forward includes of child classes as much as possible. Also, I don't want to make doStuff public, because it can really mess up the internal structure of Parent when used in the wrong circumstances.

Why does this error happen, and what is the most elegant way to solve it?

sk8forether
  • 247
  • 2
  • 9
carsten
  • 1,315
  • 2
  • 13
  • 27
  • 2
    That `Parent` that you're passing isn't you (**this**). Therefore you can't access it's parent's protected/private interface. – PaulMcKenzie May 07 '15 at 21:13
  • Also, your design is kind of strange. A Child **is-a** Parent? Maybe `Base` and `Derived` would be better names. – PaulMcKenzie May 07 '15 at 21:18

3 Answers3

3

Mostly the problem is that if C++ allowed you to access the non-public members of the referent of a base class pointer directly, then you could gain easy access to the data of an object simply by deriving from a common base.

Still this is a known loophole in the C++ type system, as shown below, where you can gain that access without modifying the base class, and without using casts or anything like that.

On the third and gripping hand, what you should do is to support the intended usage directly in the base class, by adding a static member function there, as follows:

#include <iostream>
using namespace std;

class Base
{
protected:
    void doStuff()
    {
        cout << 5 << endl;
    }

    static void doStuff( Base* p ) { p->doStuff(); }
};

class Derived : public Base
{
public:
    void pubfunc( Base* p )
    {
        doStuff( p );
    }
};

auto main() -> int
{
    Derived d;
    Base b;
    d.pubfunc( &b );
}

In my humble opinion this is most clear and elegant.

But for completeness, the type system loophole:

#include <iostream>
using namespace std;

class Base
{
protected:
    void doStuff()
    {
        cout << 5 << endl;
    }
};

class Derived : public Base
{
public:
    void pubfunc( Base* p )
    {
        (p->*&Derived::doStuff)();
    }
};

auto main() -> int
{
    Derived d;
    Base b;
    d.pubfunc( &b );
}

I recommend the static member function, though.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
0

Protected members are accessible in the class that defines them and in classes that inherit from that class. Sometimes it causes people to be confused when they see this kind of errors. But in fact you call doStuff function for Parent object, it doesn't meter if function call done inside inherited class. The result will be the same if you call doStuff function from main().

Ashot Khachatryan
  • 2,156
  • 2
  • 14
  • 30
-1
class Parent 
{
protected:
    virtual void doStuff()
    {
        std::cout << 5 << std::endl;
    }
};

class Child : public Parent 
{
protected:  
    void doStuff() override
    {
        std::cout << 8 << std::endl;
    }

public:

    void pubfunc(Parent* p)
    {
        ((Child*)p)->doStuff();
    }
};

int main()
{
    Child* c = new Child();
    Parent* p = new Parent();
    c->pubfunc(p);      // will print 5
    c->pubfunc(c);      // will print 8
    return 0;
}
Alyxion
  • 19
  • 2
  • 3
    Casting a `Parent*` to a `Child*` (without any check) smells of potentially undefined behaviour. – deviantfan May 07 '15 at 21:11
  • Yeap, you are right, answered to fast and was just was just editing :) – Alyxion May 07 '15 at 21:18
  • Edited. The way above I am using in some rare scenarios, for example when hierarchical trees of objects have to provide load and save functions which shall not be accessible by the public but by relative objects. The override of doStuff in Child is not required of course as it will anyway automatically inherit the version of Parent, just as example. – Alyxion May 07 '15 at 21:30