c++ primer(第五版)笔记 第十四章 重载运算与类型转换

// 重载运算符: 其函数名由operator关键字和定义的运算符号组成
// 其参数数量与该运算符作用的运算对象数量一致
// 对于二元运算符来说,左侧运算对象传递给第一个参数,右侧运算对象传递给第二个参数
// 除 operator() 外,其他重载运算符都不能含有默认实参
// 如果该函数是一个成员函数,则其第一个运算对象绑定到隐式的 this 指针上

// 不能被重载的运算符:
	// 域运算符 			::
	// 指向成员选择的指针 	.*
	// 成员选择符			.
	// 条件运算符			?:
	
// 不应该重载的运算符:可能无法保留运算顺序和短路求值属性
	// 逻辑与	&&
	// 逻辑或	||
	// 逗号	,
	// 取地址	&
	
// 必须定义为成员函数:
	// 赋值	=
	// 下标	[]
	// 调用	()
	// 成员访问箭头	->
	
// 应该定义为成员函数:对象状态的运算符或与给定类型密切相关的运算符
	// 符合赋值
	// 递增/碱
	
// 应该定义为普通成员函数:具有对称性的运算符可能转换任意一端的运算对象
	// 算术
	// 相等性
	// 关系
	// 位运算
	
// 重载输出运算符
	// 参数一:非常量 ostream 对象的引用
	// 参数二:常量的引用
	// 因为第一个参数必须是 ostream 对象,所以非成员函数,
	// 因为需要输出对象成员,所以友元
	
// 重载输入运算符
	// 参数一:ostream 对象的引用
	// 参数二:非常量的引用
	// 因为第一个参数必须是 iostream 对象,所以非成员函数,
	// 因为需要输出对象非公有成员,所以友元
	// 输入运算需要检查错误,并从错误中恢复
	
// 算术运算符
	// 非成员以允许左右两侧的运算对象互换
	// 如果定义了复合运算,通常使用复合运算实现

// 相等运算符
	// 通常也定义不相等,实际工作由其中一个实现,另一个调用真正实现
	
// 关系运算符
	// 定义时,遵循容器关键字的要求
	
// 赋值运算符
	// 必须为成员函数,必须返回左侧对象的引用
	// 拷贝赋值
	// 移动赋值
	// 针对其它类型的右侧对象的赋值
	
// 下标运算符
	// 容器类需要通过位置访问时
	// 返回普通引用
	// 返回常量对象的常量引用

// 递增递减运算符
	// 通常改变对象状态,建议成员函数
	// 前置版本	operator++()		返回引用,改变状态前,需要检查有效性
	// 后置版本	operator++(int) 	返回原值,使用前置版本实现,int 参数仅用于区别2个版本,并不参与运算
	
// 成员访问运算符
	// -> 必须是成员, 必须返回类的指针或自定义了 ->运算的某个类的对象
	// *一般也是,并且通常都为 const 函数
	
// 函数调用运算符
	// 定义了此运算符的类对象成为函数对象(function object) 如 lambda
	// 必须成员函数,若定义多个调用运算,需在参数个数和类型上有所区别
	
// lambda 是函数对象
	// 编译器将 lambda 翻译成未命名类的未命名对象,在该类中产生一个重载的函数调用运算符
		// eg.
			vector words;
			stable_sort(words.begin(), words.end(), [](const string &a, const string &b){return a.size() < b.size();})
			// 类似类:
			class Shortstring{
				public:
					bool operator()(const string &a, const string &b) const {
						return a.size() < b.size();
					}
			};
			// 使用该类重写:
			stable_sort(words.begin(), words.end(), Shortstring())
		
	// 对于通过引用捕获变量时,由程序确认引用对象的存在,无须再产生的类中将其存储为数据成员
	// 对于值捕获时,必须为其建立成员变量,同时构建构造函数,使用捕获的值来初始化数据成员
		// eg.
			vector words;
			size_t sz = 0;
			cin >> sz;
			auto wc = find_if(words.begin(), words.end(), [sz](const string &a){return a.size() >= sz;})
			// 类似类:
			class Sizecomp{
				public:
					Sizecomp(size_t n):sz(n){}
					bool operator(const string &a) const {
						return a.size() >= sz;
					}
				private:
					size_t sz;
			};
			// 使用该类重写:
			auto wc = find_if(words.begin(), words.end(), Sizecomp(sz));
			
// 标准库函数对象 定义于 functional.h
	// 算术运算符
		// plus
		// minus
		// multiplies
		// divides
		// modulus
		// negate
	// 关系运算符
		// equal_to
		// not_equal_to
		// greater
		// greater_equal
		// less
		// less_equal
	// 逻辑运算符
		// logical_and
		// logical_or
		// logical_not
		
// 可调用对象:
	// 函数,
	// 函数指针,
	// lambda,
	// bind创建的对象,
	// 重载的函数调用运算符
	
	// 函数表(function table),储存指向可调用对象的指针,用 map 实现
		//加法 普通函数
		int add(int a, int b){
			return a + b;
		}
		//求余 lambda
		auto mod = [](int a, int b){return a % b;};
		//除法 函数对象类
		class divide{
			public:
				int operator()(int a, int b){
					return a / b;
				}
		};
		
		//函数表
		map< string, int(*)(int, int)> binops;
		//普通函数直接插入表中
		binops.insert({"+", add});
		//对于 lambda 和 类,明显不同于表需要的值类型
		// function 模板类, 定义于 functional.h
		function f1 = add;	
		function f2 = [](int a, int b){return a % b;};	
		function f3 = divide();	
		//改写函数表类型
		map> binops{
			{"+", add},
			{"-", std::minus()},
			{"*", [](int a, int b){return a * b;}},
			{"/", divide()},
			{"%", mod}
		};
		//调用
		binops["+"](10,5);
		binops["-"](10,5);
		binops["*"](10,5);
		binops["/"](10,5);
		binops["%"](10,5);
		//使用 function 时,注意重载函数的二义性
		
// 类的类型转换	
	// 特殊的成员函数
	// operator type() const;
	// type 表示某种类型,只要该类型能作为函数的返回类型.因此不能是数组或函数,可以是指针或引用
	// 没有显式的返回类型,也没有形参,通常不改变转换对象的内容,一般为 const
	class SmallInt{
	public:
		SmallInt( int i = 0):val(i){
			if(i < 0 || i > 255)
				throw std::out_of_range("wrong smallint value!");
		}
		operator int() const {
			return val;
		}
	private:
		std::size_t val;
	}
	SmallInt si;
	si = 1;	//1 转换为 SmallInt 类型,然后operator=
	si + 3;	//si 转换为 int
	si + 3.14;	//si 转换为 int,再转换为 double
	
	如果 istream::cin 定义了 operator bool() 会发生什么?
	int n = 5;
	cin << n;	//合法,cin 隐式转换为 bool,然后再提升为 int, 然后位运算左移 n 位.

	// 为了避免上面的问题,c++11 引入显式类型转换运算符
	class SmallInt{
	public:
		SmallInt( int i = 0):val(i){
			if(i < 0 || i > 255)
				throw std::out_of_range("wrong smallint value!");
		}
		explicit operator int() const {
			return val;
		}
	private:
		std::size_t val;
	}
	si = 1;	//1 通过构造转换为 SmallInt 类型,然后operator=
	si + 3;	//错误,禁止隐式转换
	static_cast(si) + 3;	//显式请求转换
	// 表达式用于条件时,显式的转换会自动执行
	// 即 if(si + 3) 正确,
	// 在 while, if, for, !, ||, &&, ?: 条件部分都会自动发生
	
	// 避免二义性,
	// 如:A类定义了B类型参数的构造,B类定义了A类型的转换运算符
	// 又如:定义了2个转换对象都为算术类型的转换运算符

你可能感兴趣的:(c++,笔记)