【问题标题】:Is friend function getting inherited here?朋友功能在这里被继承了吗?
【发布时间】:2015-10-12 02:23:18
【问题描述】:

Derived 类中的方法fun() 是私有的。当我们通过运行时多态调用函数ptr->fun() 时,它正在执行。 但这违反了 Derived 类的封装属性。

#include<iostream>
using namespace std;

class Derived;

class Base {
private:
    virtual void fun() { cout << "Base Fun"; }
friend int main();
};

class Derived: public Base {
private:
    void fun() { cout << "Derived Fun"; }
};

int main()
{
Base *ptr = new Derived;
ptr->fun();
return 0;
}

谁能解释一下发生了什么?

【问题讨论】:

  • 朋友可以访问私人会员。您将主要成员声明为朋友,因此可以访问私有成员。 (你为什么这样做对我来说是一个奇迹)
  • @tobi303,朋友可以访问Base 而不是Derived 的私有,并且在程序运行时调用的fun()fun()Derived 类。顺便说一句,我正在玩 c++ 概念,所以遇到了这个..没什么实用的..

标签: c++ polymorphism private encapsulation


【解决方案1】:

首先,你的Derived::fun()也是virtual,因为如果派生类中的函数与基类中的虚函数有相同的声明,派生类中的函数会自动得到virtual,甚至如果没有明确指定。

其次,通过基类中的公共中间函数访问私有虚函数是完全可以的,例如,参见this answer 及其链接,尤其是Virtuality by Herb Sutter。示例代码可能是这样的

#include<iostream>
using namespace std;

class Derived;

class Base {
private:
    virtual void fun() { cout << "Base Fun"; }
public:
    void funInt() { fun(); }
};

class Derived: public Base {
private:
    virtual void fun() { cout << "Derived Fun"; }
};

int main()
{
Base *ptr = new Derived;
ptr->funInt();
return 0;
}

所以,我认为在你的情况下发生的情况类似:main 被允许访问ptr-&gt;fun(),但由于虚拟性,这个fun() 恰好是Derived::fun()

UPD:扩展评论

但这听起来是不是有点吓人.. 我的意思是,所有的功能 从基类派生的,将有它们的私有成员 基类的友元函数可以访问

不,不是Derived的所有功能都可以被Base的朋友访问,只有那些可以通过Base指针访问的功能。例如:

class Base { 
    virtual void fun();
    friend int main(); 
}
class Derived: public Base {
    virtual void fun();
    virtual void foo();
    void bar();
}

只有 Derived::fun() 可以从 main 访问:

int main() {
    Derived *ptr = new Derived;
    Base* baseptr = ptr;
    baseptr->fun(); // ok, calls Derived::fun()
    baseptr->foo(); // error, no such function in Base
    ptr->foo(); // error, foo is private
    return 0;
}

注意virtual 函数是有意可扩展的,Derivedvirtual 函数的任何覆盖意味着该函数可以通过Base 指针调用;这是virtual 函数的主要目的。如果Derived 使其覆盖函数private,它仍然应该意识到可以通过Base 指针访问该函数,因为这是virtual 函数背后的主要思想。

【讨论】:

  • 确定。但这听起来是不是有点令人担忧。我的意思是,从 Base 类派生的所有函数都可以让 Base 类的友元函数访问它们的私有成员。
  • @haris,不!只有Base 中已经存在的virtual 函数!我会在一分钟内展开答案。
  • @haris,扩大答案
  • 很好..理解.. :)
【解决方案2】:

Friend 函数从不参与继承。

这里发生了什么?
当在Base 类中定义虚方法时,会创建一个虚表,其中包含Base 类的fun 方法的地址。由于Derived 类继承了它,VTABLE 还包含Derivedfun 方法的地址。现在,由于mainBase 类的友元函数,编译器允许其成员访问main 方法,而不管它们的访问说明符如何。因此,main 获得了Derived::fun 的地址,而Derivedfun 在运行时被调用。

【讨论】:

    【解决方案3】:

    发生这种情况是因为您已将 fun 声明为虚拟。 在运行时搜索 vtable 时,它​​会找到 Derived::fun() 的条目并因此跳转到该地址。

    但是友元函数没有被继承,你可以用这个来检查。

    class Base {
    private:
        virtual void fun() { cout << "Base Fun"; }
        friend int main();
        int z = 20;
    };
    
    class Derived : public Base {
    private:
        void fun() { cout << "Derived Fun"; }
        int m = 10;
    };
    
    int main()
    {
        Base *ptr = new Derived;
        ptr->z = 10; //Accepted
        ptr->m = 5; //error
        return 0;
    }
    

    这里Derived m 的私有成员是main 无法访问的。

    【讨论】:

    • 我没听明白,程序正在从main() 函数访问派生类的私有函数。如何在基类中创建fun() 函数的虚拟效果...跨度>
    • @Nishant 我怀疑 vtables 是这样工作的.. 看到这个描述imgur.com/6e23Roa
    • @DenisZaikin 是的,显然它将是“基础乐趣”,因为 ptr 指向的对象是派生的,它有基础的子对象。
    • @haris 删除了我的评论,这是错误的,我的意思是,由于私有函数可以访问私有虚拟函数,而在你的情况下,仅仅因为方法被声明为虚拟,派生:乐趣被召唤。正如您在我的示例中看到的,并非所有私有成员都可以访问,只有虚拟成员。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-24
    • 2012-11-30
    • 1970-01-01
    • 1970-01-01
    • 2015-09-29
    • 1970-01-01
    相关资源
    最近更新 更多