1、当一个类需要转换成其他类型(任何一种前面已经定义过的类型,不一定是内置类型)时,需要使用转换函数。
例如一个类如果要转换为double,则需定义函数:
operator double() const
{
// ...
return (double)(...);
}
2、加了explicit修饰符的构造函数是不允许隐式转换的。
当构造函数只有一个实参(它可以有两个以上的形参,但是由于有默认实参,当构造该对象时,只要传入一个参数,就可以构造出该对象),就有可能在某种场景下出现隐式转换。
3、为避免同名的函数产生冲突,最好是用namespace把函数包起来。
4、成员模板可以用于模板构造函数的拷贝构造函数(一般是用于继承)。所以说泛型编程其实是兼容继承的。
5、模板主要是分成三大类:类模板、函数模板、成员模板。
6、模板特化:对于一些特别的类型要做特别的处理。与特化相对的是泛化。
7、模板偏特化:个数的偏(例如指定typename为某一种类型)和范围的偏(例如指定typename为指针类型)。
8、学习标准库最好的方法是用小工具全部测一遍它们。
9、打印C++当前的版本,以确定当前编译器是否支持C++11。
cout << _cplusplus << endl;
10、C++11支持数量不定的模板参数.
void print()
{
}
template<typename T, typename... Types>
void print(const T& firstArg, const Type&... args)
{
cout << firstArg << endl;
print(args...); // args为0个参数时,调用上面那个形参为空的函数
}
sizeof...(args); // 可以知道参数包的个数
11、使用auto关键字的时候,一定是要能让编译器能推断出该类型。
12、范围循环。
vector<double> vec;
...
for(auto elem : vec) // 值传递
{
cout << elem << endl;
}
for(auto& elem : vec) // 引用传递
{
elem *= 3;
}
13、foreach循环。
vector<int> vec;
...
foreach(int var : vec) // 值传递
{
cout << var << endl;
}
14、编译器就是以指针的角度去看待引用的。
32位编译器,指针是4个字节大小。
引用一定要有初值,告诉编译器它要代表谁。
设置r之后,r不能再重新代表其他变量。
Java里面所有的变量都是引用。
引用通常不用于声明变量,而用于参数传递和返回值。
qint64 nCnt = 10;
qint64* p = &nCnt;
qint64& r = nCnt;
qDebug() << nCnt; // 10
qDebug() << &nCnt; // 0x69fdb8
qDebug() << p; // 0x69fdb8
qDebug() << &r; // 0x69fdb8
qDebug() << sizeof nCnt; // 8
qDebug() << sizeof p; // 4
qDebug() << sizeof r; // 8---r代表nCnt
15、函数签名一样,下面二个函数不能同时存在。
int calCnt(const int& nCnt) { ... }
int calCnt(const int nCnt) { ... }
函数签名不包含函数的返回类型。
函数重载不考虑函数的返回类型。
注意,const是函数签名的一部分。
16、析构的顺序与构造的顺序相反。
17、当类含有一个或多个虚函数,该对象在内存中就会存在一个虚指针。
类的父类有虚函数,子类也会有虚函数,也就有虚指针。
所谓继承是继承函数的调用权,不是函数的内存大小。
18、虚指针指向虚表。
虚表存放函数指针,指向虚函数所在的位置。
如果子类重写了父类的虚函数func,则子类对象的虚表中不再含有父类虚函数func的指针。
19、动态绑定的意义在于 通过类new的指针p找到虚指针,然后通过虚指针找到虚表,然后在虚表中看看找到哪个函数。
(*(p->vptr)[n])(p); // 后面的参数(p)的意思是传递this指针
或
(* p->vptr[n] )(p);
20、this就是调用函数的那个对象的地址。
21、通过对象调用,就是静态绑定。
B b;
A a = (A)b;
a.vFunc(); // 这样是调用父类A的虚函数vFunc
22、当一个函数要加const(这个函数不打算改变class的data)却没有加const的时候,一个const对象调用该函数就会有问题(常量对象不能调用非常量成员函数)。
int getCnt() const { return nCnt; }
const只能放在成员函数的后面,不能放在全局函数的后面。
23、当成员函数的const和non-const版本同时存在,const对象只会调用const版本,non-const对象只会调用non-const版本。
24、::new是强制调用全局的意思。::是全局范围操作符。
全局函数也是可以重载的。
25、 如果一个没有虚函数的类A的大小是12字节,则它有虚函数的时候,类A的大小是16字节。
如果一个类A的大小是12字节,则
new A();就是12字节,而new A[5];则是12*5+4=64字节,其中多出来的那4个字节存放变量5.
类似的,如果一个有虚函数的类A,new A[5];的大小是16*5+4=84字节。
26、new的另一用法。举个例子,可以使用new(extra) 扩充内存申请量。
size_t extra;
Rep* p = new(extra) Rep;
void* operator new(size_t s, size_t extra)
{
return Allocator::allocate(s+extra*sizeof(charT));
}