文章目录
目标完成情况
- 两道LeetCode ----- 没做,实在没心思做。。有点懒
- 看侯捷视频,独立实现Complex类 ----- 基本完成,但是在侯捷的动态数组分配的地方听得有点蒙蔽,我感觉他可能讲错了。
- csapp第7章看完前3节 -------- 前面比较短,看了5节。
知识复盘
1. C++语法实战
整个上午都在Linux下用vim尝试独立实现Complex这个类。主要是为了熟悉C++的操作符重载、const的使用等基本语法,同时也体会到了ide的方便性,因为在shell下每次都要重新编译,然后运行,还是挺麻烦的。遇到了很多bug,这部分我不默写了。
1.1 关于内联函数
主要将其视为宏定义的替代版即可,或者说升级版。所以,一个函数,他是不是内联函数,和他是成员函数还是全局函数是没有关系的。按照侯捷的说法,所有的函数都最好添加inline关键字,意思是建议编译器给她作为内联函数来编译,但这仅仅是建议。
1.2 二元操作符的全局形式的重载
需要传入两个参数,而不像成员函数的形式,只要传入一个,成员函数之所以只要传入一个参数,是因为,隐式地传入了一个this指针,指向了调用者自身。
1.3 关于隐式构造函数(non explicit)
隐式的调用构造函数,构造出来的是右值,右值是不能被non-const的引用绑定的,因此这个时候需要用const参数来接收。我开始时没有将参数设为const的,遇到了下面的错误:
error: invalid initialization of non-const reference of type ‘Complex&’ from an rvalue of type ‘Complex’
将接收参数改成const就好了。
1.4 关于操作符‘<<’的重载
这个操作符的重载一定要是全局形式的,因为否则的话使用起来会非常丑陋,不符合需求。
需要传入两个参数,第一个参数是ostream对象,一定要是non-const的,而第二个参数一定是const的,因为我们只是要将第二个参数输出,并不会改变他。如下:
ostream& operator << (ostream& os, const Complex& x){
return os << x.real() << "+" << x.image() << "i";
}
1.5 关于赋值运算符‘=’的重载
由于Complex内部不带指针,因此这只是最基本的赋值运算符的重载。
我想说的是,这个运算符通常建议设置成成员函数的形式,这和<<相反。这样可以确保左边的值是对象,从而不会出现将一个对象赋值给常量的情形。如下:
Complex& operator = (const Complex& b){
this->re = b.re;
this->im = b.im;
return *this;
}
还有一点,我认为是<<和=运算符重载的共同点,就是内部都是使用了C++语言自带的“原始”操作符。例如<<的重载,利用了ostream的<<, 而‘=’的重载,在内部实现的时候,也还是利用了语言自带的‘=’。
1.6 关于带指针的类的设计
这个部分主要是下午看了侯捷的视频,没有动手实现,主要讲了三大函数:拷贝构造函数,拷贝赋值运算符,析构函数。在带指针的类中,我们通常需要自己重新实现这三个函数,而不是使用编译器自动生成的。
然后讲了一些深拷贝浅拷贝的东西。
让我感觉收获最大的地方是,在重载拷贝赋值运算符的时候,检测是否为自我赋值是很有必要的,否则的话,一旦真的发生了自我赋值,就会出错,因为在我们的实现中,我们会首先将原先的数据删除,然后创建空间,然后拷贝,而如果是自己给自己赋值的话,那么在删除数据之后,就再也找不到原先的数据了,从而无从拷贝。这就很搞笑了。
inline
String& String::operator=(const String& str){
if(this == &str){ // 检测自我赋值,不可少!!!!
return *this;
}
// 删除原有数据和空间
delete[] m_data; /// 虽然只有一个指针,但是一定要加[]
// 创建新的合适大小的空间
m_data = new char[strlen(str.m_data)+1];
// 数据拷贝
strcpy(m_data, str.m_data);
return *this;
}
2.《深入理解计算机系统》第7章 链接
看了前5节。
稍微有点蒙蔽。
但是我还是认为这一章非常重要,在将来的实际工程中,会经常用到此处的知识。下面的内容属于强行默写。
链接概述
链接主要做两件事情:
- 符号解析
- 地址重定位
在链接之前已经经历了预处理器、编译器、汇编器的处理,得到了二进制可重定位目标文件。但是这些文件是不可执行的,为什么呢?两个原因:
- 目标文件中有很多占位符,需要填充地址。
- 多个目标文件中的符号的相对地址没有确定,我们要的是一个目标文件,而不是多个。
这两个问题都将由链接器来解决,也就是完成符号解析和地址重定位。说得好像有点啰嗦。
符号解析概述
首先链接器看到的是目标代码(也称为目标文件),而目标代码是分节的,节是怎么分出来的呢?
目标文件有一个起始的16字节来标识目标文件的开始。后面有个字段指出了一个节(节头部表),而这个节当中又存储了其他所有节的地址,从而就可以分出所有的节了。
有了节又怎样呢?节是用来分类存放信息的。
例如.text 节是用来存放编译后的代码的。而.symtab节是用来存放本目标文件中的所有符号信息的。而.data就是我们常说的静态区(数据区),他会存放已经初始化的全局变量和静态变量,例如程序中有一句static int x = 3,这个x不是放在栈中的,而是放在.data节中的,可见这个x在编译之后、连接之前就存在了。
后面详述了.symtab节,这个节就是存放符号表的节,也就是存放了所有的符号信息,每个符号有哪些信息?也就是说这个表有哪些字段?分别介绍了每个字段,暂时不太理解具体有什么用。下图是一个例子:
明天再看吧。总之在搞清楚符号和符号表之后,应该就可以解析了,所谓解析,我暂时的理解就是将符号换成相应的地址。有点懵逼。
明天加油,今天效率还可以吧,毕竟动手了,我相信只要动手实操,就一定是很有进步的。当然还要结合书本,才能引导思考,否则就是机械操作了。孔子曾经说过:学而不练则惘,练而不学则原地转圈圈。而我想要的是螺旋上升哈哈。
明日目标
- 两道LeetCode
- 侯捷的基础视频快速过完,因为感觉视频看太多收获很小了,我缺的不是理论,而是实操。
- csapp第7章起码看完符号解析,地址重定位开个头。这部分比较难,感觉。