友元函数和友元类(friend)

友元(friend)

定义在类的外部,但需要在类的内部进行说明的普通函数或类,与其他函数和类的区别是在前面加上关键字friend。友元不是成员函数,但它可以访问类中的私有成员,破坏了类的特性(封装)。

友元关系是单向的,不具对称性(即 A 是 B 的友元,但 B 不一定是 A 的友元)和传递性(即 B 是 A 的友元,C 是 B 的友元,但是 C 不一定是 A 的友元)

友元函数

声明在类外部的普通函数,但需要在类的内部说明,使用friend来修饰(不是类的成员函数)来与类内部的成员函数加以区别,可以在友元函数中访问类的私有成员(通过对象参数来访问私有数据成员),但是普通的类外部函数无法访问类的私有成员只能访问公有成员。

语句位置与访问描述无关

#pragma warning(disable : 4996)
#include 
using namespace std;

class A
{
public:
    //通过对象参数来访问私有数据成员
    friend int Add(A &pa,int a,int b);
private:
    int m_a, m_b;
};

int Add(A &pa, int a,int b)
{
    pa.m_a = a;
    pa.m_b = b;
    return pa.m_a + pa.m_b;
}

int main()
{
    A a1;
    cout << "a = " << Add(a1, 10,20)<< endl;
    system("pause");
    return 0;
}

友元类

在类中使用关键字friend修饰说明另一个类,就可以作为一个友元类存在,即一个类可以作另一个类的友元。也就是说这个友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类的私有成员和保护成员。

friend class 类名(即友元类的类名)

class A
{
    //破坏了类A的封装性
    friend class B;
public:
    int GetA()
    {
        return  m_a;
    }
private:
    int m_a;
};

class B
{
public:
    void SetValue(int val)
    {
        a.m_a = val;
    }
    void GetValue()
    {
        cout << "a = " << a.GetA() << endl;
    }
private:
    A a;
};

int main()
{
    B b;
    b.SetValue(10);
    b.GetValue();
    system("pause");
    return 0;
}

友元函数实现操作符重载

一般情况下用友元函数重载<<,>>操作符

  • istream 和 ostream 是 C++ 的预定义流类
  • cin 是 istream 的对象,cout 是 ostream 的对象
  • 运算符 << 由ostream 重载为插入操作,用于输出基本类型数据
  • 运算符 >> 由 istream 重载为提取操作,用于输入基本类型数据
  • 用友员函数重载 << 和 >> ,输出和输入用户自定义的数据类型
friend ostream & operator<<(ostream &out, MyString &s);
friend istream & operator>>(istream &input, MyString &s);

后面会详细分析,这里先提一下推荐友元函数重载<<,>>操作符,其他时候能不能使用友元,视情况而定。

为什么要用到友元

如果要在类A中访问类B中的私有成员和保护成员,从而达到共享同一函数的前提下,我们可以使用友元类和友元函数,但是使用友元破坏了类的封装性,而能实现类之间的数据共享,减少系统开销,提高效率,在实际的开发中根据需要选择。

总结

1、友元是单向性的,即类B是类A的友元,类A不一定是类B的友元,也不是传递性的,即类B是类A的友元,类C是类B的友元,类C不一定是类A的友元。

2、友元不能被继承,即类B是类A的友元,类的子类不一定是类A的友元。

3、一般情况下,用友元函数重载<<、>>操作符,

4、友元函数没有this指针,所需操作数都必须在参数表中显示声明

 

你可能感兴趣的:(C\C++基础)