继承和指向受保护成员的指针

Inheritance and pointers to protected members

本文关键字:成员 指针 受保护 继承      更新时间:2023-10-16

我目前正在为我正在编写的游戏创建一个基本的UI系统。它被组织为一个节点树。我正在尝试编写它,以便只有根节点才能在其他节点上调用update方法。我以为我理解C++继承,但它又一次嘲笑我的无能。我试着在下面创建一个简单的例子:

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();
}

当我试图编译这个GCC时,会出现错误:

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

包括root在内的所有节点都继承了Base的update_internal()方法,我不明白为什么保护它很重要。我认为派生类只能访问私有成员和方法。

只能从派生类的实例中调用基类的受保护/私有函数(当然,除非使用friend s)。因此,派生类只能访问其基部分的私有/受保护成员,而不能访问其他基部分的成员。在您的情况下,您通过引用中的Base*来调用它

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

所以编译器会抱怨。

只需与Base和Root成为好友;

class Base
{
    friend class Root; // <- yes,this
    public:
        virtual ~Base() { }
    protected:
        virtual void update_internal() = 0;
};

这是Template Method模式的一个常见示例
Root类的公共方法公开了需要在内部实现的内容。

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;
};