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;
}