Boolan极客班C++开发工程师笔记。
1.conversion function(转换函数)
对于系统的预定义基本类型数据,C++提供了隐式类型转换和显式类型转换两种类型转换方式:
int a=1,sum=0;
double b=1.111;
sum=a+b; //隐式转换
sum=(int)(a+b); //显式转换
sum=int(a+b); //显式转换
对于用户自定义的类类型与其他数据类型实现转换,C++提供了两种方法:
1.1 通过类型转换函数进行类型转换;
使用方法与操作符重载相似,定义见如下例子
operator double() const {
return (double) (m_numerator/m_denominator);
}
调用方法:
Fraction f(3,5);
double d=4+f;//调用operator double() 将f转为0.6
补充:
①类型转换函数只能作为类的成员函数,不能作为友元函数或者普通函数,因为被转换的是本类对象;
②在函数名前面不能指定函数类型,函数没有参数;
③函数中必须有return语句,即函数返回值的类型是函数声明中指定的类型;
④一个类可以定义多个类型转换函数,C++编译器会根据函数名自动调用相应的类型转换函数。
1.2 通过转换构造函数进行类型转换(non-explicit-one-argument ctor);
转换构造函数是将一个其他类型的数据转换成为类的对象,例子:
Fraction(int num, int den = 1)
: m_numerator(num), m_denominator(den) { }
除此之外,我们还需要重载运算符
Fraction operator + (const Fraction& f) {
return .....;
}
调用方法:
Fraction f(3,5);
Fraction d2=f+4;//调用non-explicit ctor 将4转为Fraction(4,1),然后调用operator+
1.3 explicit关键字
1.1和1.2两种方法共用时会出现歧义,解决方法:
在转换构造函数之前加上explicit,表示不允许将其他类型的数据转换成类对象。
2.pointer-like classes,关于智能指针
把class做的像pointer,但又希望它比pointer多些东西,这就是智能指针。首先,class里面一定有个真正的指针;其次,它得能代表一般的指针,因此就必须有指针的基本使用*和->,这需要操作符重载来实现。
3.pointer-like classes,关于迭代器
迭代器的作用是指向容器中的元素,也包含了指针的功能,具体代码见下面两张图。
4.function-like classes ,所谓仿函数
设计一个class让它的行为像一个函数。函数是怎么样的呢?有个(),所做出的对象可以接受()。
标准库里有很多的仿函数,其实都是些class,所谓的仿函数就是类通过重载()来实现类似函数的功能,返回一个值。
具体的例子见下图
5.标准库中的仿函数的奇特模样
6.namespace
namespace的作用主要是防止函数或者类的名称冲突。
比如我们要测试20个函数,我们可以把每个函数单独放入到一个namespace中去,这样做每个函数都是完全独立的,不用考虑名称上的冲突。
7.模板
class template 和 function template前面的笔记中已经提到过。
7.1member tempate
先看下图的例子
class就是个模板,而成员里还有个模板,即黄色部分,称为成员模板。T1、T2可以变化,U1、U2也可以变化。
为什么我们需要成员模板呢?见下图
鲫鱼和麻雀分别属于鱼类和鸟类的子类,用他们的类对象作为相应父类的初始化值肯定是可以的,但是一旦如上图所示pair类接收鱼类和鸟类类型后,该类的构造函数只能接受鱼类和鸟类作为初始化参数。这个时候我们就需要成员模板来解决pair类接受鲫鱼和麻雀类作为它构造函数的初始化类型。
7.2 specialization,模板特化
泛化就是模板,特化的意思就是指你作为一个设计者,你可能要面对一些特殊的类型要单独处理。
解释:上面的是泛化,下面的是特化。且下面的都对()进行重载。
7.3partial specialization,模板偏特化
泛化又分为:全泛化(full specialization)和(partial specialization,模板偏特化(局部特化))
偏特化:个数上的偏,范围上的偏。
如下图,个数上的偏特化。一定要从左边到右边,不能跳着来
范围上的偏特化,如下,T是任意类型,现在把它范围缩小成指针,如下
7.4template template parameter,模板模板参数
模板的参数本省也可以是模板,具体代码如下:
temeplate<tpyename T,
template <typename T>
class Container
>
Class XCls {
private: Container<T> c;
......
};
template<typename T>
using Lst=list<T,allocator<T>>;
如果作为模板参数的模板只需要一个参数,我们可以写成如下格式:
XCls<string,Lst> mylst2;
如果需要的参数不止一个,且没有默认值,就不能这么写:
XCls<string,list> mylst1;
8.关于C++标准库
标准库包含了容器(Container),算法(ALgorithms),迭代器(Iterators),仿函数(Functors)等。
最好的学习方法是把里面的方法全部自己用一遍!
9.C++11后的一些新语法
9.1variadic template
void print()
{
}
template<typename T, typename... Types>
void print(const &T, const Types&...args) {
cout << firstArg << endl;
print(args...);
}
...就是一个所谓的pack(包)
用于template parameters,就是template parameters pack(模板参数包)
用于function parameter types,就是function parameter types pack(函数参数类型包)
用于function parameters,就是function parameters pack(函数参数包)
9.2 auto
auto是C++中的一个语法糖,可以让编译器自动推算变量类型。
不要极端地认为全部都使用auto,首先作为初学者在没有完全清楚变量的类型的情况下不建议,其次并不是所有情况下都能使用auto,比如下面这种情况就不能使用auto:
9.3range-base for
这是for循环的一种新的写法,也是C++11的一种语法糖,依赖于迭代器,格式如下:
for (declaration : expression){
statments;
}
expression必须是一个序列,比如vector,数组,string等。
注意点:pass by value和pass by reference的不同作用,前者不改变expression里面的对象,后者可以