【问题标题】:C++ virtual method: access rights, friends & CoC++ 虚方法:访问权限、好友 & Co
【发布时间】:2013-06-07 12:13:30
【问题描述】:

我在理解如何管理虚拟方法的访问权限时遇到了一些麻烦。我做了两个小代码示例,但我无法理解它是如何工作的。

代码示例 1

第一个代码包含 3 个类:一个母类Foo 和两个派生类。 Baz 类看起来有点像 Composite。有一个虚方法,但它是受保护的。

class Foo
{
protected:
    virtual void doIt() = 0;
};

class Bar : public Foo
{
protected:
    void doIt()
    {}
};

class Baz : public Foo
{
protected:
    void doIt()
    {
        M_foo->doIt(); // Error here
    }
private:
    Foo* M_foo;
};

在尝试编译 (Visual C++ 2010) 时,我收到一个错误:我无法在派生类中从指向 Foo 的指针调用 doIt。所以,我的理解是“我不能调用这个方法,因为它实际上可以调用另一个我无权调用的方法(例如 Bar 的那个)”。

代码示例 2

我决定稍微改变一下代码的设计并设计一个函数而不是虚拟方法。但是,要访问受保护的方法,我需要与我的函数添加友谊。

class Foo
{
    friend void doItPlease( Foo* foo);

protected:
    virtual Foo* getChild() = 0;
};

class Bar : public Foo
{
protected:
    Foo* getChild()
    { return 0;}
};

class Baz : public Foo
{
protected:
    Foo* getChild()
    {
        return M_foo;
    }
private:
    Foo* M_foo;
};

void doItPlease( Foo* foo)
{
    Foo* myFoo( foo->getChild() );
};

这段代码编译得很好。问题是我不明白为什么:我只将基类声明为friend,而不是子类,并且没有继承友谊。但是现在,当我从函数中调用 getChild 时,就好像我会调用一个我无权使用的方法(例如 Baz 中的那个)。

谁能解释一下与虚拟方法相关的权利是如何管理的?

【问题讨论】:

    标签: c++ inheritance virtual friend


    【解决方案1】:

    这些是受保护的规则。它们允许访问基类子对象,但不允许访问像您这样的任何不相关的实例。

    如果你用谷歌搜索受保护,你会发现建议首先避免它,只使用私有和公共,中间很少是好的。

    关键是您从基类的角度定义私有性。如果允许从外部进行某些操作,则未知方是独立的还是恰好是子类无关紧要。唯一相关的属性是它是否被信任。

    如果特定的派生类是与基类一起定义的,请随意交友,保持规则不变。

    【讨论】:

    • 好的,对于第二个代码,从这个角度来看,这看起来是合乎逻辑的。如果我理解正确,'friend' 允许我的函数在 *Foo 的每个实例上调用虚拟方法,而继承只允许我在 'this' 上调用虚拟方法(如果是,可以通过 Foo::doIt 完成不纯)。
    【解决方案2】:
    class Foo
    {
    public:
        friend class Baz;
    protected:
        virtual void doIt() = 0;
    };
    
    
    class Baz : public Foo
    {
    public:
        Baz(Foo* foo)
            : M_foo(foo)
        {
        }
    
    protected:
        void doIt()
        {
            M_foo->doIt();
        }
    private:
        Foo* M_foo;
    };
    

    【讨论】:

    • 谢谢你的回答,但这不是我想做的。 M_foo 不指向类本身(它不是“this”),而是指向另一个对象(真的很像在 Composite 中)。
    • 然后我将 Baz 定义为 Foo 中的朋友
    • 第二个解决方案都不是。我需要 Baz 从 Foo 继承才能将 Baz* 存储为 Foo*(Baz 中的 M_foo 实际上可能是 Baz*)
    • 那么 Baz 确实应该继承自 Foo。我会改的
    【解决方案3】:

    这不能工作,因为 Foo::doIt 是一个未定义的虚方法方法

    class Baz : public Foo
    {
    protected:
        void doIt()
        {
            Foo::doIt();
        }
    };
    

    但是如果你有这样的东西应该可以正常工作

    class Baz : public Foo
    {
        Baz() 
        {
             M_foo = new Bar();
        }
    protected:
        void doIt()
        {
            M_foo->doIt();
        }
    private:
        Foo* M_foo;
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-22
      • 2012-11-30
      • 1970-01-01
      • 2017-06-20
      • 2012-11-01
      • 2011-12-11
      • 1970-01-01
      相关资源
      最近更新 更多