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的第一个参数初始化。