3

I'm currently creating a basic UI system for a game I'm writing. It's organized as a tree of nodes. I'm trying to write it so that only the root node can call the update method on other nodes. I thought I understood C++ inheritance but it's once again laughing at my incompetence. I've tried to create a bare-bones example below:

class Base
{
    public:
        virtual ~Base() { }

    protected:
        virtual void update_internal() = 0;
};

class Node_A : public Base
{
    protected:
        virtual void update_internal() { std::cout << "Update Node A" << std::endl; }
};

class Node_B : public Base
{
    protected:
        virtual void update_internal() { std::cout << "Update Node B" << std::endl; }
};

class Root : public Base
{
    public:
        void add_node (Base* node) { m_nodes.push_back(node); }

        void update()
            {
                for (auto& node : m_nodes)
                {
                    node->update_internal();
                }
            }

    protected:
        std::vector<Base*> m_nodes;
        virtual void update_internal() { }
};


int main()
{
    Node_A alpha_node;
    Node_B beta_node;
    Root root_node;

    root_node.add_node(&alpha_node);
    root_node.add_node(&beta_node);

    root_node.update();
}

When I try to compile this GCC gives me the error:

error: 'virtual void Base::update_internal()' is protected

All of the nodes including root inherit the update_internal() method from Base, I don't understand why it matters that it is protected. I thought it was only private members and methods that derived classes couldn't access.

curiousguy
  • 8,038
  • 2
  • 40
  • 58
Fibbs
  • 1,350
  • 1
  • 13
  • 23
  • 2
    http://stackoverflow.com/questions/11631777/accessing-a-protected-member-of-a-base-class-in-another-subclass – Amadeus Nov 26 '15 at 17:22

4 Answers4

4

You can only call a protected/private function of a base class only from an instance of the derived class (unless of course you use friends). So the derived class can only access the private/protected members of its base part, not of some other base. In your case, you call it via a reference to a Base* in

for(auto& node : m_nodes)
     node->update_internal();

so the compiler complains.

vsoftco
  • 55,410
  • 12
  • 139
  • 252
2

Just befriend Base and Root;

class Base
{
    friend class Root; // <- yes,this
    public:
        virtual ~Base() { }

    protected:
        virtual void update_internal() = 0;
};
xinaiz
  • 7,744
  • 6
  • 34
  • 78
1

This is a stock example for the Template Method pattern.
The public method of the Root class exposes, what's needed to be implemented internally.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
1
class Base
{
protected:
    virtual void update_internal() = 0;

    static void DoUpdate( Base *node )
    {
        node->update_internal();
    }
};

class Root : public Base
{
public: 
    void update()
    {
        for (auto node : m_nodes)
        {
            Base::DoUpdate( node );
        }
    }
protected:
    virtual void update_internal() override {}
    std::vector<Base*> m_nodes;
};
Rabbid76
  • 202,892
  • 27
  • 131
  • 174