CPP_运算符重载及友元

友元

类的友元函数是定义在类外部,但有权访问类的所有私有成员和保护成员。友元函数需要在类中声明,但是友元函数不属于成员函数。

友元的关键字是friend。

友元函数有三种实现:全局函数做友元,类做友元和成员函数做友元。

哪些全局函数、成员函数或类作为类的友元是由类定义的(在类内部声明),而不能从外部强加友情。因此,尽管友元被授予从外部访问类的私有部分的权限,但它们并不与面向对象的编程思想相背离;相反,它们提高了共有接口的灵活性。

友元声明可以位于public、protected或private部分,其所在的位置无关紧要。

全局函数做友元

#include <iostream>
#include <string>
using namespace std;

class Building
{
    //goodFriend是Building的好朋友,可以访问Building的私有成员
    friend void goodFriend(Building* building);
  
public:
    Building() :m_SittingRoom("客厅"), m_BedRoom("卧室") {}
    string m_SittingRoom;   //客厅

private:
    string m_BedRoom;       //卧室
};

//全局函数
void goodFriend(Building* building)
{
    cout << "好朋友全局函数正在访问" << building->m_SittingRoom << endl;

    cout << "好朋友全局函数正在访问" << building->m_BedRoom << endl;
}

void test01()
{
    Building b;
    goodFriend(&b);
}

类做友元

#include <iostream>
#include <string>
using namespace std;

class Building;

//类做友元
class GoodFriend
{
public:
    GoodFriend();
    void visit();       //参观函数访问building中的属性
    Building* building;
};

class Building
{
    //类做友元
    friend class GoodFriend;
public:
    Building();
    string m_SittingRoom;
private:
    string m_BedRoom;
};

//类外写成员函数
Building::Building()
{
    m_SittingRoom = "客厅";
    m_BedRoom = "卧室";
}

GoodFriend::GoodFriend()
{
    //创建建筑物对象
    building = new Building;
}

void GoodFriend::visit()
{
    cout << "好朋友正在访问" << building->m_SittingRoom << endl;
    cout << "好朋友正在访问" << building->m_BedRoom << endl;
}

void test01()
{
    GoodFriend gFriend;
    gFriend.visit();
}

成员函数做友元

#include <iostream>
#include <string>
using namespace std;

class Building;

class GoodFriend
{
public:
    GoodFriend();

    void visit();       //让visit()可以访问Building中的私有成员
    void visit2();      //让visit2()不可以访问Building中的私有成员

    Building* building;
};

class Building
{
    //成员函数做友元
    friend void GoodFriend::visit();
public:
    Building();
    string m_SittingRoom;
private:
    string m_BedRoom;
};

Building::Building()
{
    m_SittingRoom = "客厅";
    m_BedRoom = "卧室";
}

GoodFriend::GoodFriend()
{
    building = new Building;
}

void GoodFriend::visit()
{
    cout << "visit函数正在访问" << building->m_SittingRoom << endl;
    cout << "visit函数正在访问" << building->m_BedRoom << endl;
}

void GoodFriend::visit2()
{
    cout << "visit2函数正在访问" << building->m_SittingRoom << endl;
    //cout << "visit2函数正在访问" << building->m_BedRoom << endl;
}

void test01()
{
    GoodFriend gFriend;
    gFriend.visit();
    gFriend.visit2();
}

类和友元类互相调用问题

类内声明友元成员函数时,需要访问友元类,所以友元类要提前定义或前向声明(forward declaration)。

但是友元类中一般会定义类的对象,所以也要前向声明类。两者互相调用时会报错未声明。

一般的使用流程是:声明类->友元类定义(其中只包含方法声明,实际的定义放到类后)->类定义(类中声明友元)->函数实现。(如上面示例显示)

需要使用友元的另一种情况是,函数需要访问两个类的私有数据。从逻辑上看,这样的函数应该是每个类的成员函数,但这个不可能。它可以是一个类的成员,同时是另一个类的友元,但有时将函数作为两个类的友元更合理。

运算符重载

两种重载方法

1)成员函数

a + b => a.operator+(b); 一个参数

2)友元函数

a + b => operator+(a, b); 两个参数。

friend 将某个类或函数声明为另一个类的友元,就可以访问另一个类的private成员了。

不能重载运算符:., .*, ::, ?: (共四个)

示例重载左移运算符配合友元可以实现输出自定义数据类型。

#include <iostream>
using namespace std;

class Person
{
    friend ostream& operator<<(ostream& cout, Person& p);
    friend void test01();
public:
    Person() {};
    Person(int a, int b)
    {
        this->m_A = a;
        this->m_B = b;
    }

    //利用成员函数重载 << 运算符,p.operator<<(cout) 简化为 p << cout,不是想要的结果
    //不会利用成员函数重载运算符,因为无法实现cout在左侧
    //void operator<<(cout) {}

private:
    int m_A;
    int m_B;
};

//只能利用全局函数重载左移运算符
//本质:operator<<(cout, p),简化为cout << p
//ostream对象只能有一个
ostream& operator<<(ostream& cout, Person& p)
{
    cout << "m_A = " << p.m_A << "\nm_B = " << p.m_B;
    return cout;
}

void test01()
{
    Person p;
    p.m_A = 10;
    p.m_B = 10;

    cout << p << endl;
}
posted @ 2018-09-09 21:49  yuxi_o  阅读(238)  评论(0编辑  收藏  举报