从派生类方法到基类成员的友谊

时间:2014-07-15 00:29:54

标签: c++ inheritance encapsulation friend access-control

我想知道是否有办法让派生类的方法成为其基类的朋友。类似的东西:

class Derived;
class Base
{
    int i, j;
    friend void Derived::f();
protected:
    Base();
};

class Derived : public Base
{
public:
    void f();
};

我得到的错误是:

error: C2027: use of undefined type 'Derived'
see declaration of 'Derived'
error: C2248: 'Base::i' : cannot access private member declared in class 'Base'
see declaration of 'Base::i'
see declaration of 'Base'
error: C2248: 'Base::j' : cannot access private member declared in class 'Base'
see declaration of 'Base::j'
see declaration of 'Base'
error: C2027: use of undefined type 'Derived'
see declaration of 'Derived'

我整天都在努力。我发现的关于友谊的一切都只使用分离的类,而不是继承。

3 个答案:

答案 0 :(得分:2)

没有直接的方式:Base需要Derived::f的定义,而Derived也需要定义Base类。

但是没关系,你不应该这样做,你可以按照优先顺序:

  • Base
  • 中提供受保护的访问者
  • 让整个Derived班级成为朋友(一般不需要)
  • 你可以使用一个中级助手类,它只转发这个特定方法的调用,并给它友谊:

示例here

class Base;
class Derived;

class Helper final
{
    friend class Derived;

    public:
        void f(Base* base);
    private:
        Helper() {}
};

class Base
{
    int i, j;
    friend class Helper;
protected:
    Base() {}
};

class Derived : public Base
{
public:
    void f();
private:
    Helper helper;
};

void Helper::f(Base* base)
{
    base->i = 10; base->j = 5;
    std::cout << "Help !" ;
}

void Derived::f()
{
    helper.f(this);
}

答案 1 :(得分:1)

解决这类问题的一种方法是应用规则“如果它是一个东西,那么它就是一个类。”

@quantdev解决方案就在这些方面。

基于评论:

  

假设我有两个类都派生自基类和   拥有相同的私人会员。为什么不保存一些代码   将该成员放在基类中并提供朋友访问权限   两个需要该成员的派生类。假设其他派生的   类根本无法访问该成员。这就是我的意思   试图实现

[我知道这不符合指定的问题,但可能是您需要的。]

我通过将公共元素分解为中间类来解决这个问题:

class Base
{
public:
    Base();
    virtual ~Base() = 0;
};

class Derived : public Base
{
public:
    void f()
    {
        i = 1;
    }
private:
    int i, j;
};

class Foo : public Derived
{};

class Bar : public Derived
{};

class Fred : public Base
{};

答案 2 :(得分:0)

我不知道是否有可能完全按照自己的意愿行事(虽然在我看来应该是这样) - 而且我有兴趣看到其他答案显示它是如何 - 但是还有其他几种方法可以达到你想要的效果。我假设您一般都在询问这种情况 - 也就是说,您也对可能存在许多不同派生类的情况感兴趣,并非所有这些都需要,不应该访问{{1}的私有字段(当然,你应该创建这些字段Base)。

首先,最简单的方法是将protected朋友设为Derived,尽管这感觉就像是黑客(部分因为它不是允许对Base进行Base的任何封装,这绝对不是最佳选择。

在我看来,在封装方面更好的方法是创建一个外部“免费”(非成员)函数,它是Derived的朋友(如果你是Base也需要)。这解决了循环编译器错误,但遗憾的是仍然失去了作为“Derived操作”的概念语义。