c++之友元

本文详细介绍了C++中的友元机制,包括友元的作用、使用场景、如何使用友元函数和友元类。通过实例展示了友元如何提高程序效率,同时探讨了友元对封装性和安全性的潜在影响。友元函数和友元类的声明与调用方式也得到了阐述,以及友元关系的特点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.为什么要引用友元

提高程序运行效率,既减少了类型和安全性检查及调用时间的开销,但它破坏了类的封装型和隐藏性,使得非成员函数可以访问类的私有成员。

2.使用场景

1)运算符重载的某些场合;

2)2个类要共享数据

3)异类若想要访问private的数据,必须声明为友元

3.使用友元函数

友元函数是在类中使用关键字friend修饰的非成员函数。

由于友元函数不是成员函数,所以不存在this指针,必须通过对象来访问。

友元仅是打破了外部访问中的private的权限。A声明为B的友元,A就可以通过B的对象访问B的私有成员。

1)要访问非static成员,需要对象做参数;

2)要访问static成员或全局变量,则不需要对象做参数;

3)如果做参数的对象是全局对象,则不需要对象做参数;

友元函数的位置

        是类外函数,所以它的声明可以放在类的私有段或公有段且没有区别。

友元函数的调用

        可以直接调用友元函数,不需要通过对象或指针。

4.实战

4.1 普通函数做友元函数

class Pos
{
public:
    friend Pos MovePos(Pos &current, Pos &move);

    Pos(int x=0, int y=0, int angle=0)
        :m_x(x)
        ,m_y(y)
        ,m_angle(angle)
    {}
    ~Pos()
    {}


    void PrintPos()
    {
        cout << "current pos : ( " << m_x << ", " << m_y << ", " << m_angle << ")" << endl;
    }

private:
    int m_x;
    int m_y;
    int m_angle;
};

Pos MovePos(Pos &current, Pos &move)
{
    Pos temp;
    temp.m_x = current.m_x + move.m_x;
    temp.m_y = current.m_y + move.m_y;
    temp.m_angle = current.m_angle + move.m_angle;
    return  current;
}
int main()
{
    Pos one(1,2,3);
    Pos two(10,20,30);
    Pos three = MovePos(one,two);

    three.PrintPos();
    return 0;
}

4.2 成员函数做友元函数

1)友元函数是其它类的成员函数

2)必须先定义包含成员函数的类(比如说A),再在另外一个类(比如说B)中将该成员函数声明为友元函数。此时虽然这个友元函数是A的成员函数,该友元函数仍然称为非成员函数(对于B来说)

前向声明:是一种不完全的类型(incomplete type)声明,即只需要提供类名(无需提供实现)即可。

特点:

1)不能定义对象

2)仅可用于定义指向这个类型的指针或引用

3)仅用于声明不是定义,仅可以作为形参类型或函数的返回值类型(定义在类外实现)

#include <iostream>
#include <cmath>
using namespace std;
 
 
//前向引用声明,否则报错 error: 'Point' does not name a type
class Point;
 
class Line{
public:
    //这时不能使用这样的形式进行初始化:Line(Point p1,Point p2):p1(p1),p2(p2){}
    //因为此时Point的结构尚未定义,error: field 'p1' has incomplete type
    Line(Point p1,Point p2);
    Point& getP1(); //把引用当做函数返回值
    Point& getP2();
    float dist();
private:
    //不可以这样定义成员变量:Point p1,p2;因为此时Point结构尚不完善
    Point &rp1,&rp2;//类(引用)的组合
    //这里也可以用Point *rp1, *rp2;
    //这样在构造函数时,可以不用传入Point的对象,而是在Line的构造函数中动态分配内存
    //即
    Line(int x, int y, int y, int y1){
        rp1 = new Point(x, y);
        rp2 = new Point(x1, y1);
    }
 
};
 
class Point{
public:
    Point(int x = 0,int y = 0):x(x),y(y){}
    int getX(){ return x;}//内联函数
    int getY(){ return y;}
    void showData();
    //声明友元成员函数
    friend float Line::dist();
private:
    int x,y;
};
 
void Point::showData(){
    cout << "x: " << x << ", y: " << y << endl;
}
 
//Line类函数的延迟实现开始
 
//当一个类的成员变量是引用时,需要在初始化列表中初始化引用
//否则报错:error: uninitialized reference member
Line::Line(Point p1,Point p2):rp1(p1),rp2(p2){}
Point& Line::getP1(){
     return rp1;
}
Point& Line::getP2(){
     return rp2;
}
float Line::dist(){
    double x = rp1.x - rp2.x;
    double y = rp1.y - rp2.y;
    return static_cast<float>(sqrt(x*x + y*y));
}
//Line类函数的延迟实现结束
 
 
int main()
{
    Point p1(1,1),p2(4,5);
    p1.showData();
    p2.showData();
    Line line(p1,p2);
    cout << "the distance is : " << line.dist() << endl;
    return 0;
}

4.3 友元类

#include <iostream>
#include <cmath>
using namespace std;
 
class Point{
public:
    Point(int x = 0,int y = 0):x(x),y(y){}
    int getX(){ return x;}//内联函数
    int getY(){ return y;}
    void showData();
    //声明友元类,否则编译不通过,error: 'int Point::x' is private
    friend class Line;
private:
    int x,y;
};
 
void Point::showData(){
    cout << "x: " << x << ", y: " << y << endl;
}
 
 
class Line{
public:
    Line(Point p1,Point p2):p1(p1),p2(p2){}
    Point getP1(){ return p1;}
    Point getP2(){ return p2;}
    float dist();
private:
    Point p1,p2;//类的组合
};
 
float Line::dist(){
    double x = p1.x - p2.x;
    double y = p1.y - p2.y;
    return static_cast<float>(sqrt(x*x + y*y));
}
 
int main()
{
    Point p1(1,1),p2(4,5);
    p1.showData();
    p2.showData();
    Line line(p1,p2);
    cout << "the distance is : " << line.dist() << endl;
    return 0;
}

5.友元性质

1)友元关系是不能传递的,如A是B的友元,B是C的友元,但A不是C的友元

2)友元关系是单向的,A是B的友元,A可以访问B的私有属性,反之不成立

3)友元关系是不被继承的,A是B的友元,但A的派生类不是B的友元

### 如何在C++中声明C++中,`friend`关键字用于授予特定函数或类访问权限。需要注意的是,声明仅指定访问级别,并不构成对函数的一般声明[^1]。 #### 函数的声明方式 当希望某个非成员函数能够访问类中的私有成员时,可以在类定义内部使用如下形式来声明该函数为: ```cpp class MyClass { public: friend void myFriendFunction(MyClass& obj); private: int privateData; }; ``` 上述代码片段表明 `myFriendFunction()` 是 `MyClass` 的朋,因此它可以访问 `MyClass` 中的所有私有数据成员和保护成员。 #### 类之间的好关系 除了单个函数外,还可以让整个类成为另一个类的朋。这允许前者完全访问后者所有的私有部分以及受保护的部分: ```cpp class FriendClass; class OriginalClass { friend class FriendClass; // 声明FriendClass作为OriginalClass的好 private: int secretValue; }; // 定义FriendClass... ``` 通过这种方式建立起来的关系意味着 `FriendClass` 能够自由操作 `OriginalClass` 内部任何未公开的信息。 #### 成员函数作为 如果想使某类的一个成员方法成为其他类的对象的操作者,则可以这样写: ```cpp class AnotherClass { public: void doSomething(); friend void SomeOtherClass::specificMethod(AnotherClass&); }; ``` 这里指定了 `SomeOtherClass::specificMethod()` 方法对于 `AnotherClass` 实例具有特权级别的访问权。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值