侯捷 面向对象高级编程 (下) 学习笔记

1、conversion fuction(转换函数)

​
class Fraction{
	public :
		Fraction(int num, int den = 1)
		: m_numerator(num), m_denominator(den)	{ }
		operator double() const{
		return (double (m_numerator)) / m_denominator;
		} 
	private :
		int m_numerator;
		int m_denominator;
}; 

int main(){
	Fraction a(3, 4);
	double i = 4 + a;
	cout << i << endl; 
}

​

将 a 转换为 double 类型 。

输出为 : 4.75

注意: 转换函数没有返回类型。

2、non-explicit-one-argumrnt ctor

上段代码中的构造函数即为一个non-explicit-one-argumrnt ctor,所谓one-argument 是指构造对象时仅需指定一个实参值即可,因为den有默认值。

​
class Fraction{
	public :
		Fraction(int num, int den = 1)
		: m_numerator(num), m_denominator(den)	{ }
		Fraction operator + (const Fraction& fra){
			return Fraction(m_numerator * fra.m_numerator + fra.m_numerator * 
            m_numerator, m_denominator * fra.m_denominator );
		} 
	/*	operator double() const{
		return (double (m_numerator)) / m_denominator;
		} */ 
	private :
		int m_numerator;
		int m_denominator;
}; 

int main(){
	Fraction a(3, 4);
	Fraction b = a + 4;
}

​

正因为non-explicit,所以可通过4调用Fraction(4, 1),从而不会出错。若加上explicit,则不允许这种转换,会出错。

注意: 若改为 Fraction b = 4 + a; 则会出错。为什么呢?因为默认是操作符前面的对象调用成员函数,而4只是个int值而不是成员对象。

3、 conversion fuction 与 non-explicit-one-argumrnt ctor 同时存在

class Fraction{
	public :
		Fraction(int num, int den = 1)
		: m_numerator(num), m_denominator(den)	{ }
		Fraction operator + (const Fraction& fra){
			return Fraction(m_numerator * fra.m_numerator + fra.m_numerator * m_numerator, m_denominator * fra.m_denominator );
		} 
		operator double() const{
		return (double (m_numerator)) / m_denominator;
		}  
	private :
		int m_numerator;
		int m_denominator;
}; 

int main(){
	Fraction a(3, 4);
	Fraction b = a + 4;
}

这时就会报错,因为既可以将a转为double类型,又可将4转为成员对象,有两条路可走就会出错。编译器不知道走哪条路。

可能你会好奇,明明b的类型就规定为Fraction,那不就只能将4转为成员对象吗?可是C++编译器不能根据返回值确定调用哪个重载函数

4、explicit-one-argumrnt ctor

		explicit Fraction(int num, int den = 1)
		: m_numerator(num), m_denominator(den)	{ }

在构造函数前加上explicit,告诉编译器不能进行自动转换。

5、pointer-like class,属于智能指针

是指class产生出来的对象像指针,什么样的操作符能用到指针上,该class就要实现相同的操作。指针一般有*与->两个操作符。

template
class shared_ptr{
	public :
		T& operator * () const{
			return *px; 
		}
		T* operator -> () const{
		    return px; 
		}
		shared_ptr(T* p) : px(p) {	}
	private :
		T* px;
		long* pn;

};

struct Foo{
	void method(){
	}
};

int main(){
	shared_ptr sp(new Foo);
	Foo f(*sp); 
	sp->method();
}

->这个操作符在class中的实现可能会令人费解,->这个操作符有传递下去的特点,不会消失,所以可以返回为px,

此时sp->method()等同于px->method()。

6、pointer-like class,属于迭代器

迭代器也像一个指针,但是加在它身上的操作符会更多,比如++,--,==,!=

7、function-like class,所谓仿函数

就是重载了( )运算符的类,至于为什么要有仿函数,还没说。

8、namespace

一个组的人写的代码中可能会冲突,那么如何避免这种冲突呢?每个人都给自己的代码加个namespace,并给这个namespace取个名字。再使用的时候通过名字::函数名调用。

9、class template

template
class Complex{
	public :
		Complex(T r = 0, T i = 0)
		: re(r), im(i) { }
		T real() const {return re;}
		T imag() const {return im;}
	private :
		T re, im;
}; 

使用时用尖括号指明T的类型即可

	Complex c1(2, 3);
	Complex c2(3.4, 7.8);

10、function template

不用指定类型,直接给实参即可。

11、member template

类模板里面再套一个模板,只能上转

12、specialization 模板特化

13、模板偏特化

a、个数的偏 从左到右指定某几个类型(一定要按顺序指定,不可以跳着指定,也不可以全指定(因为全指定就变成了特化))

b、范围的偏 由任意变为指针

14、模板模板参数

模板A的参数本身也是一个模板B,模板B可以用模板A的第一个参数初始化。

 

你可能感兴趣的:(C++学习笔记)