一、友元
友元可以允许其他类或者函数访问自己的非共有成员,如果类想把它的函数作为友元,只需要增加一条以friend开头的函数声明即可。
1.1 添加外部函数作为友元
以下一个学生类,类中保存了学生的年龄、名字以及性别信息:
1 2 3 4 5 6 |
class stu_st { private: int age; string name; char sex; }; |
现在希望在类外面以函数的形式来计算两个学生的年龄之和,因为age
成员是私有的,所以目前类外部的函数是无法获取到学生年龄,这个想法无法完成。但是有了友元之后,这个想法就能实现了。只要在类中添加友元定义,外部再实现函数就可以了:
1 2 3 4 5 6 7 8 9 |
class stu_st { friend int figure_age(const stu_st &a, const stu_st &b); // ... }; // 实现计算年龄函数 int figure_age(const stu_st &a, const stu_st &b) { return a.age + b.age; } |
友元是不区分共有和私有的,以友元修饰的函数即使声明在private域,外部也是能访问的。
1.2 以外部类作为友元
新增一个老师类,老师能获取学生的年龄:
1 2 3 4 5 6 7 8 9 10 11 12 |
class teacher_st; class stu_st { friend class teacher_st; // ... }; class teacher_st { public: unsigned int get_stu_age(const stu_st &stu) { return stu.age; } }; |
1.3 静态成员变量
当类中存在静态变量时,友元类和函数也是能直接访问这个变量的。
以下代码声明了一个teacher_st
作为老师类,声明了一个stu_st
作为学生类,学生类中有一个静态变量total_count
表示学生的总数,老师作为友元类来获取这个数量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include <iostream> using namespace std; class teacher_st; class stu_st { friend class teacher_st; private: static unsigned int total_count; }; class teacher_st { public: unsigned int get_stu_count() { return stu_st::total_count; } }; unsigned int stu_st::total_count = 10; int main() { teacher_st t; cout << t.get_stu_count() << endl; return 0; } |
运行结果:
二、运算符重载
2.1 运算符重载语法
运算符重载给类提供了大大的便利,使得自定义类型也能和内置类型一样使用系统操作符。
运算符重载的语法:
1 |
void operator+(const stu_st &s); |
各元素说明:
void
:返回值类型operator+
:表示重载运算符+
s
:运算符的参数
运算符重载有几种不同的写法,可以写在类中,也可以写在类外面。
在类中声明
以学生类为例,重载小于符号<
使得类可以直接通过年龄大小作为对比:
1 2 3 4 5 6 7 8 9 10 11 12 |
class stu_st { private: unsigned int age; string name; public: stu_st(int age, string name) : age(age), name(name) { } // 重载小于符号 bool operator<(const stu_st &x) const { return this->age < x.age; } }; |
在类外面声明
因为类外面的函数无法直接访问类内部数据,因此,类外面的函数需要被声明为类的友元函数。
1 2 3 4 5 6 7 8 9 10 11 12 |
class stu_st { private: unsigned int age; string name; public: // 声明重载操作符> friend bool operator>(const stu_st &, const stu_st &); }; bool operator>(const stu_st &a, const stu_st &b) { return a.age > b.age; } |
注意
在类内部重载操作符,编译器默认会把this作为第一个参数传入,因此,重载时无需再传入当前类对象本身。例如:
1 |
bool operator<(const stu_st &x) const |
这就表示用当前对象和x对象作对比。而外部声明的函数,因为没有封装在类中,不能传入this指针,因此声明时需要传入对象本身。即:
1 |
friend bool operator>(const stu_st &, const stu_st &); |
2.3 重载输入输出运算符
重载输入和输出运算符需要注意的一个问题是:与iostream标准库相关的运算符重载,必须是非成员函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#include <iostream> #include <ostream> #include <string> using namespace std; class stu_st { private: unsigned int age; string name; public: stu_st() {}; friend istream &operator>>(istream &, stu_st &); friend ostream &operator<<(ostream &os, const stu_st &stu); }; // 重载输出运算符 ostream &operator<<(ostream &os, const stu_st &stu) { os << "Name: " << stu.name << "\tAge: " << stu.age; return os; } // 重载输入运算符 istream &operator>>(istream &is, stu_st &stu) { is >> stu.name >> stu.age; return is; } int main() { stu_st stu; cin >> stu; cout << stu; } |
测试效果:
评论