• C++ 虚函数和友元


    虚函数具有动态联编性,在类族中有强大功能;友元函数具有跨类访问的功能,本质却是一种对封装的破坏。

    先看这样一个例子:

    #include<iostream>
    using namespace std;
    class A;
    class B
    {
    private:
        int x;
        void print()
        {
            cout<<x<<endl;
        }
    public:
        B(int i = 0)
        {
            x = i;
        }
        friend class A;
    };
    class A
    {
    public:
        void func(B b)
        {
            b.print();
        }
    };
    class D: public B
    {
    public:
        D(int i):B(i) {}
    };
    int main()
    {
        cout<<sizeof(A)<<" "<<sizeof(B)<<" "<<sizeof(D)<<endl;
        D d(99);
        A a;
        a.func(d);
        return 0;
    }

    程序执行结果为:
            1 4 4
            99
    上例中,A是B的友元类,A中的所有成员函数都为B的友元函数,可访问B的私有成员函数。友元类A大小为1,基类和派生类大小都是4,友元类A不是基类B的一部分,更不是派生类D的一部分。

     从上例看,友元似乎能够被继承,A的函数func这能访问B的派生类D嘛!这不基类的友元函数或友元类能够访问派生类的私有成员!

    但若将上例中的继承关系改为私有继承,则:

       class D: private B
       a.func(d);  // error C2243: “类型转换”: 从“D *”到“const B &”的转换存在,但无法访问   

    我们知道:public继承是一种“is a”的关系,即一个派生类对象可看成一个基类对象。所以,上例中不是基类的友元被继承了,而是派生类被识别为基类了

    再比如这样一个例子

    #include<iostream>
    using namespace std;
    class B;
    class A
    {
    private:
        void print()
        {
            cout<<"A::print"<<endl;
        }
    public:
        friend class B;
    };
    class B
    {
    public:
        void func(A a)
        {
            a.print();
        }
    };
    class D: public B { };
    
    int main()
    {
        A a;
        D d;
        d.func(a);
        return 0;
    }

    程序执行结果为:
            A::print
    上例中,B为A的友元类,D是B的派生类,D继承了基类B的友元函数func,它能访问A的私有成员。由此可知一个友元类的派生类,可以通过其基类接口去访问设置其基类为友元类的类的私有成员,也就是说一个类的友元类的派生类,某种意义上还是其友元类
    但若在上例D中新增加个成员函数,该函数是不能访问A私有成员的。

    class D: public B
    {
    public:
            void test(A a){ a.print(); } // error C2248: “A::print”: 无法访问 private 成员(在“A”类中声明)
    };
    #include<iostream>
    using namespace std;
    class A;
    class B
    {
    private:
        void print()
        {
            cout<<"B::print"<<endl;
        }
    public:
        friend class A;
    };
    class A
    {
    public:
        void func(B b)
        {
            b.print();
        }
    };
    class D: public B
    {
    private:
        void print()
        {
            cout<<"D::print"<<endl;
        }
    };
    int main()
    {
        D d;
        A a;
        a.func(d);
        return 0;
    }

    程序执行结果为:
        B::print
    和前两例类似,友元关系并没有被继承,仅是派生类对象当成了一个基类对象来用,因此输出“B::print”。
    若将上例print函数改为虚函数并通过多态来访问,就可以达到类似于友元可以继承的效果。

    class A;
    class B
    {
    private:
        virtual void print()
        {
            cout<<"B::print"<<endl;
        }
    public:
        friend class A;
    };
    class A
    {
    public:
        void func(B* pb)
        {
            pb->print();
        }
    };
    class D: public B
    {
    private:
        virtual void print()
        {
            cout<<"D::print"<<endl;
        }
    };
    
    int main()
    {
        D d;
        A a;
        a.func(&d);
        return 0;
    }

     这本质上就是满足了多态的三个条件:

    必须存在继承关系;   

    继承关系中必须有同名的虚函数,并且它们是覆盖关系。  

    存在基类的指针,通过该指针调用虚函数。

  • 相关阅读:
    ES6中的新特性
    怎样优化CPU
    es6 一些小知识
    ECMAScript有6种继承方式(实现继承)
    angula的factory service provider
    angular的继承作用域通信
    MVP和MVC的区别
    判断浏览器版本语句大全
    IScroll5+在ios、android点击(click)事件不兼容解决方法
    css中单位px和em,rem的区别
  • 原文地址:https://www.cnblogs.com/wkfvawl/p/12427496.html
Copyright © 2020-2023  润新知