【C++】02-C++面向对象高级编程(下)-笔记(侯捷系列)

2021/7/6 22:10:00

本文主要是介绍【C++】02-C++面向对象高级编程(下)-笔记(侯捷系列),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

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));
}



这篇关于【C++】02-C++面向对象高级编程(下)-笔记(侯捷系列)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程