【问题标题】:friendship from derived class method to base class members从派生类方法到基类成员的友谊
【发布时间】:2014-09-05 01:21:35
【问题描述】:

我想知道是否有办法让派生类中的方法成为其基类的朋友。比如:

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'

我整天都在为此苦苦挣扎。我发现的所有关于友谊的东西都只使用了分离的类,而不是继承。

【问题讨论】:

  • 当你尝试这个时,你从编译器得到什么错误?您采取了哪些措施来解决这些错误?
  • 我正在使用 Visual C++ 12 编译器

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


【解决方案1】:

不,没有直接的方法:Base 需要定义 Derived::fDerived 也需要定义它的 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);
}

【讨论】:

  • 我认为这是个好主意,只是 Helper 类的 f() 函数是公共的,这意味着任何人都可以继承它并使用它来侵犯基类的隐私。如果我将 Helper 构造函数声明为 private 和同一个类 final 以防止继承怎么办。最后,我让派生类成为 Helper 类的朋友,以便在其自己的 f() 函数中访问其构造函数?
  • 是的,我们应该让它成为最终的(参见我的编辑),并且还可以让助手成为派生类的成员
  • 如何将Helper::Helper 设为私有并让Derived 成为助手的朋友?目前,任何人都可以创建Helper
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    我不知道是否有可能完全按照您的意愿去做(尽管在我看来应该是这样)——而且我很想看到其他答案来说明它是如何做到的——但是还有其他几种方法可以实现您想要的。我假设您在一般情况下询问这种情况 - 也就是说,您也对可能存在许多不同派生类的情况感兴趣,并非所有派生类都需要,不应该访问 Base 的私有字段(否则你当然应该把这些字段设为protected)。

    首先,最简单的做法是让Derived 成为朋友classBase,尽管这感觉像是一种 hack(部分原因是它不允许任何封装Base 相对于 Derived) 并且在这里绝对是次优的。

    在我看来,就封装而言,一个更好的方法是创建一个外部“免费”(非成员)函数,它是 Base 的朋友(如果你也需要,也可能是 Derived) .这绕过了循环编译器错误,但不幸的是仍然失去了作为“派生操作”的概念语义。

    【讨论】:

    • 事实上,这正是重点。使基类成员受保护将允许访问所有派生类。我不想那样。但假设我有两个类都派生自基类并具有相同的私有成员。为什么不通过将该成员放在基类中并提供对需要该成员的两个派生类的朋友访问来节省一些代码。假设其他派生类根本无法访问该成员。这就是我想要实现的目标。
    猜你喜欢
    • 2012-09-16
    • 2013-10-08
    • 1970-01-01
    • 2017-04-14
    • 2016-01-10
    • 1970-01-01
    • 1970-01-01
    • 2017-11-08
    • 2016-05-21
    相关资源
    最近更新 更多