28-友元的尴尬能力

注:博客中内容主要来自《狄泰软件学院》,博客仅当私人笔记使用。

测试环境:Ubuntu 10.10

GCC版本:9.2.0

 

一、友元的概念

1)什么是友元

        -    友元是C++中的一种关系

        -    友元关系发生在函数与类之间或者类与类之间

        -    友元关系是单向的不能传递

             左边的函数是右边类的友元。

 

二、友元的用法

1)在类中以friend关键字声明友元

2)类的友元可以是其它类或者具体函数        

3)友元不是类的一部分

4)友元不受类中访问级别的限制

5)友元可以直接访问具体类的所有成员

 

三、友元的语法

1)在类中用friend关键字对函数进行声明

class Point
{
    double x;
    double y;

    friend void func(Point& p);    //这行代码使func和Point建立了友元关系,func可以随意访问Point
};

void func(Point& p)  //全局函数
{


}

分析:

        友元函数func()可以直接使用类Point中所有成员和方法。

 

编程实验
友元的使用初探
28-1.cpp
#include <stdio.h>
#include <math.h>

class Point
{
    double x;
    double y;
public:
    Point(double x, double y)
    {
        this->x = x;    //私有成员变量赋值
        this->y = y;    //y赋值给当前对象成员变量y(即,this->y)
    }
    
    double getX()
    {
        return x;
    }
    
    double getY()
    {
        return y;
    }
       
    friend double func(Point& p1, Point& p2);  //如果不是友元关系,不能访问私有成员
};

double func(Point& p1, Point& p2) //求两点间距离
{
    double ret = 0;
    //直接访问对象的私有属性(一般不能再类外访问私有属性)
    ret = (p2.y - p1.y) * (p2.y - p1.y) +
          (p2.x - p1.x) * (p2.x - p1.x);
   
    //不用友元
    /*  //这样多次调用get函数,效率低
    ret = (p2.getY() - p1.getY()) * (p2.getY() - p1.getY()) +
          (p2.getX() - p1.getX()) * (p2.getX() - p1.getX());
    */

    ret = sqrt(ret);
    
    return ret;
}

int main()
{
    Point p1(1, 2);
    Point p2(10, 20);
    
    printf("p1(%f, %f)\n", p1.getX(), p1.getY());    //查看赋值
    printf("p2(%f, %f)\n", p2.getX(), p2.getY());
    printf("|(p1, p2)| = %f\n", func(p1, p2));    //打印两点间距离
    
    return 0;
}

操作:

1) 使用友元:g++ 28-1.cpp -o 28-1.out编译正确,打印结果:

p1(1.000000, 2.000000)
p2(10.000000, 20.000000)
|(p1,p2)| = 20.124612

2) 不使用友元:

double func(Point& p1, Point& p2) //求两点间距离
{
    double ret = 0;
    
    ret = (p2.y - p1.y) * (p2.y - p1.y) +
          (p2.x - p1.x) * (p2.x - p1.x);
   
    //不用友元
    //这样多次调用get函数,效率低
    ret = (p2.getY() - p1.getY()) * (p2.getY() - p1.getY()) +
          (p2.getX() - p1.getX()) * (p2.getX() - p1.getX());

    ret = sqrt(ret);
    
    return ret;
}

分析:

        虽然将函数声明为友元,也可以使用普通方法访问数据。

 

四、友元的尴尬

1)友元是为了兼顾C语言的高效而诞生的

2)友元直接破坏了面向对象的封装性

3)友元在实际产品中的高效是得不偿失的

4)友元在现代软件工程中已经逐渐被遗弃

 

五、注意事项

1)友元关系不具备传递性

2)类的友元可以是其它类的成员函数

3)类的友元可以是某个完整的类(友元类所有方法都可以访问原始类的私有成员和保护成员)

        -    所有的成员函数都是友元

 图:友元关系不具备传递性

 

编程实验
友元的深入分析
28-2.cpp
#include <stdio.h>

class ClassC
{
    const char* n;
public:
    ClassC(const char* n)
    {
        this->n = n;
    }
    
    friend class ClassB;  //声明B是C的友元
};

class ClassB
{
    const char* n;
public:
    ClassB(const char* n)
    {
        this->n = n;
    }
    
    void getClassCName(ClassC& c)
    {
        printf("c.n = %s\n", c.n);
    }
    
    friend class ClassA; //声明A是B的友元
};

class ClassA
{
    const char* n;
public:
    ClassA(const char* n)
    {
        this->n = n;
    }
    
    void getClassBName(ClassB& b)
    {
        printf("b.n = %s\n", b.n);
    }
    
    void getClassCName(ClassC& c)
    {
        printf("c.n = %s\n", c.n);  //A不是C的友元,关系不能传递。因此不能访问ClassC中的私有数据n(有传递性就可以访问了)
    }
    
};

int main()
{
    ClassA A("A");
    ClassB B("B");
    ClassC C("C");
    
    A.getClassBName(B);    //声明友元关系,就可以调用类中的成员函数
    B.getClassCName(C);    //声明友元关系,就可以调用类中的成员函数
    
    return 0;
}

操作:

1) g++ 28-1.cpp -o 28-1.out编译错误:

28-1.cpp:5:14: error: 'const char* ClassC::n' is private
    const char* n;
28-1.cpp:48:26: error: within this context
    printf("c.n = %s\n", c.n);
错误:'const char* ClassC::n' 是私有的

私有不能访问,证明友元是单向的,不具备传递关系。

 

小结

1)友元是为了兼顾C语言的高效而诞生的

2)友元直接破坏了面向对象的封装性

3)友元关系不具备传递性

4)类的友元可以是其它类的成员函数

5)类的友元可以是某个完整的类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值