十九、成员指针(了解)
1、成员变量指针
1)定义
类型 类名::* 成员指针变量名 = &类名::成员变量;
2)使用
对象.*成员指针变量名;
对象指针->*成员指针变量名;
".*"
:成员指针解引用运算符;
"->*"
:间接成员指针解引用运算符;
注意:
成员变量指针的本质是类中特定成员在对象中的相对地址;
2、成员函数指针
1)定义
返回类型 (类名::*成员函数指针)(形参表) = &类名::成员函数名;
2)使用
(对象.*成员函数指针)(实参表);
(对象指针->*成员函数指针)(实参表);
二十、操作符重载
1、双目操作符的重载 L#R
1.1 运算类双目操作符
eg:实现两个复数:(1 + 2i) + (3 + 4i) = 4 + 6i
a. 表达式的结果为右值;
b. 左右操作数既可以为左值,也可以为右值;
实现方式:
1)成员函数形式
L#R的表达式可以被编译器翻译成L.operator#(R)
的成员函数调用的形式,该函数的返回结果就是表达式的值。
2)全局函数形式
L#R的表达式也可以被编译器翻译成::operator#(L, R)
的全局函数调用形式,该函数的返回结果就是表达式的值。
注意:
通过friend关键字,可以把一个全局函数声明为某个类的友元函数,在友元函数中可以访问类中任何成员;
1.2 赋值类双目操作符
a. 左操作数必须是左值;
b. 右操作数可以是左值,也可以是右值;
c. 表达式的值是一个左值,而且就是左操作数的自身;
实现方式:
1)成员函数形式
L#R ==> L.operator#(R)
2)全局函数形式
L#R ==> ::operator#(L, R)
2、单目操作符的重载 #O
2.1 计算类的单目操作符 -(取负) ! ~
a. 操作数既可以是左值也可以是右值;
b. 表达式返回结果是右值;
实现方式:
1)成员函数形式
L#R ==> O.operator#()
2)全局函数形式
L#R ==> ::operator#(O)
2.2 自增减运算符:
1)前缀自增减:
操作数是左值,返回值也是左值(就是操作数自身)
实现方法:
1)成员函数形式:#O- ==> O.operator#()
2)全局函数形式:#O- ==> operator#(O)
2)后缀自增减:
操作数是左值,返回值是右值(返回自增减前的数值)
实现方法:
1)成员函数形式:#O- ==> O.operator#(哑元参数)
2)全局函数形式:#O- ==> operator#(O)
3、插入和提取操作符 << >>
功能:
实现自定义类型的输出和输入的操作;
注意:
只能用全局函数形式(friend)实现;
#include <iostream>
ostream cout;
istream cin;
friend ostream& operator<<(ostream& os, const RIGHT& right);
friend istream& operator>>(istream& is, const RIGHT& right);
eg:
// cout.operator<<(a);
// operator<<(cout, a);
cout << "hello" << endl;
cout << a << b << endl;
练习:
实现3×3矩阵类,实现以下操作符重载:
+
-
+=
-=
-
(取负) 前后++/--
<<
扩展:*
*=
1 2 3 9 8 7 10 10 10
4 5 6 + 6 5 4 = 10 10 10
7 8 9 3 2 1 10 10 10
class M33{
public:
M33(int a[][3]){
for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
m_a[i][j] = a[i][j];
}
private:
int m_a[3][3];
};
4、下标操作符的重载 [ ]
功能:让一个对象当做数组一样去使用;
注意:
非常对象返回左值,常对象返回右值;
string s("hello");
cout << s[1] << endl; // e
s[0] = 'H';
cout << s << endl; // "Hello"
const string a2("hello");
s2[0] = 'H'; // error
5、类型转换操作符
功能:实现自定义的类型的转换;
operator 目标类型(void)const{...}
6、new/delete运算符
static void* operator new(size_t size){..}
static void operator delete(void* p){..}
7、其它
1)函数操作符”()”:可以把一个对象当做函数去使用
2)解引用(取目标)”*”可以把一个对象当做指针使用;
3)间接成员访问运算符”->”可以把一个对象当做指针使用;
… …
总结:操作符重载的限制
1)不是所有的操作符都能重载,以下操作符不能重载:
作用域限定操作符 - - - - - - - - - - "::"
直接成员访问操作符 - - - - - - - – "."
成员指针解引用操作符 - - - - - - -".*"
条件操作符 - - - - - - - - - - - - - - - -"? :"
字节长度操作符 - - - - - - - - - - - - "sizeof"
类型信息操作符 - - - - - - - - - - - - "typeid()"
2)如果一个操作符所有的操作数都是基本类型,则该操作符无法重载;
3)操作符重载不会改变编译器预定义的优先级;
4)操作符重载无法改变操作数的个数;
5)无法通过操作符的重载机制发明新的操作符;
Kenneth A.Reek[著]、徐波[译]:《《c和指针》 - 人民邮电出版社 - 2008-04-01
Peter Van Der Linden[著]、徐波[译]:《c专家编程》 - 人民邮电出版社 - 2008-02-01
陈正冲:《c语言深度解剖》 - 北京航空航天大学出版社 - 2012-07