1. 友元
(1)友元函数
①是一种允许非类成员函数访问类的私有成员的一种机制;可以把一个函数指定为类的友元,也可以把整个类指定为另一个类的友元;
②友元函数在类作用域外定义,但需要在类体中进行声明(friend),声明的位置不限,放在公有、私有、保护部分都一样;
③主要作用:提高了程序的运行效率,减少了类型和安全性检查及调用的时间开销;
#include <iostream>
using namespace std;
class Test
{
public:
Test() = default;
Test(int num):m_num(num){}
~Test() = default;
friend void print(const Test &t);
private:
int m_num;
};
void print( const Test &t )
{
cout<<t.m_num<<endl;
}
int main(int argc, char **argv)
{
Test t1(7);
print(t1);
return 0;
}
(2)友元类
①需要前置声明:只是单纯的声明有这个类,但是不知道这个类的具体构造;
②友元关系是单向的,友元关系不能被传递,不能被继承;
(3)友元成员函数
①需要在类前面前置声明友元类,成员函数才可以访问友元类的成员;
②不能互为成员函数;
#include<iostream>
using namespace std;
class Date;//对Date类的提前"友元类"引用声明
class Time
{
public:
Time(int, int, int); //声明构造函数
void display(Date &);
private:
int hour;
int sec;
int minute;
};
class Date
{
public:
Date(int, int, int); //声明构造函数
friend void Time::display(Date &);
private:
int mouth;
int day;
int year;
};
void Time::display(Date &d)//display的作用是输出年月日,时分秒
{
cout << d.year<< "/" << d.mouth << "/" << d.day<<" ";
cout << Time::hour << ":" << minute << ":" << sec << endl;
}
Date::Date(int m, int d, int y)
{
mouth = m;
day = d;
year = y;
}
Time::Time(int h, int m, int s)
{
hour = h;
minute = m;
sec = s;
}
int main(void)
{
Time t1(10, 13, 56);
Date d1(4, 15, 2019);
t1.display(d1);
return 0;
}
2. 运算符重载
(1)运算符重载本质上是函数重载,不仅是语法上的方便,也是另一种函数调用的方式;
(2)重载的两个部分:①成员函数重载;②友元函数重载;
(3)语法
//成员函数重载
//成员函数原型的格式:
函数类型 operator 运算符(参数表)
//成员函数定义的格式:
函数类型 类名::operator 运算符(参数表)
{
函数体;
}
//友元函数重载
//友元函数原型的格式:
friend 函数原型 operator 运算符(参数表);
//友元函数定义的格式:
friend 函数类型 类名::operator运算符(参数表)
{
函数体;
}
(4)运算符重载规则
①运算符重载不允许发明新的运算符;
②不能改变运算符操作对象的个数;
③运算符被重载后,其优先级和结合性不会改变;
④不能重载的运算符
运算符 | 符号 |
作用域解析运算符 | :: |
条件运算符 | ?: |
直接成员访问运算符 | . |
类成员指针引用的运算符 | .* |
sizeof运算符 | sizeof |
⑤选择成员函数重载方式还是友元函数重载方式?
一般情况下,单目运算符做好重载为类的成员函数,双目运算符最好重载为类的友元函数;
但这些双目运算符不能重载为类的友元函数:=、()、[ ]、->。
类型转换运算符只能以成员函数方式重载;
流运算符只能以友元的方式重载(因为重载成员函数重载方式,左侧运算量就是对象本身,但是<<和>>的左侧运算符是cin 或 cout而不是对象本身,所以不能够使用成员函数重载方式,只能申明为友元函数);
//重载<<输出流运算符示例
friend ostream & operator<<(ostream &out, const String &str); //友元函数声明
ostream & operator<<(ostream &os, const String & str) //友元函数定义
{
out<<str.str_;
return out;
}
⑥类型转换运算符重载:必须是成员函数、不能是友元函数;不能指定返回返回类型,因为已经指定了;
//operator int()
Integer::operator int() //注意重载这里没有返回值
{
return n_;
}