目标完成情况
- 两道算法题 — 只做了一道,链表相加
- 侯捷的视频
- linux扫盲视频----没看
- csapp第三章数组和异质数据结构
白天所学尚存记忆
链表相加
这个不难,典型的做法将两个链表的数据全部入栈,然后逐个pop出来相加,生成新的链表头插到一个新的链表中去。
侯捷的C++视频
复习了之前的笔记。尽量回顾如下:
关于const
- const修饰函数,只能是类的成员函数可以用,全局函数的函数体不能用const修饰,这个其实很好理解,因为const修饰的函数意味着不会改变类的成员变量,而全局函数没有成员变量的概念,因此当然不应该使用const修饰。
- const修饰对象。这种对象不能调用非const函数,因为非const函数意味着可能会对成员进行改变,而const对象是绝对不能改变成员的,因此可能会造成矛盾,比如说const对象调用了一个非const函数,而这个函数刚好真的改变了某个成员,那么就矛盾了。所以C++语言不允许这种调用
- 还有一点,虽然说非const对象既可以访问非const成员函数(这是很显然的,不懂const或者不考虑const问题的人都是这么做的),也能访问const成员函数,但是C++认为的理想情况是:非const对象就调用非const函数,const对象调用const函数。如何实现这一点呢?可以对“同一个”函数进行重载,按照是否有const修饰来区分,因为C++的函数签名是需要考虑函数体的const的。为什么要各自调用各自的函数呢?因为const函数的实现通常更为简洁,效率更高,而非const函数由于可能存在修改和覆盖,所以要考虑copy on write问题。
- const修饰返回值和参数等问题暂时没有仔细考虑。
关于操作符重载
我自己写了很简单的demo,现在理解较为具体深刻了。
- C++ 将操作符看做函数名。所以重载操作符的时候会有返回值,参数,和函数体。
- C++的成员函数在调用的时候,一定会默认传入一个this指针,this指针指向谁?谁调用,就指向谁。 在看到一个操作符的时候,我们只要观察其左边的值是谁,比如说是a,那么就是a调用了这个操作符,那么我们就应该在a的类里面实现这个操作符函数。在实现的时候,通常会用到this,而this就是指向a的。
- 操作符是否需要重载,以及重载成什么样的问题,和const类似,都是由类的设计者决定的。也就是说,在我们设计一个类的开始,我们就知道了这个类的对象是如何相加的,如何比较大小的,等等。
关于转换函数
- 通常说的转换函数,是指将一个类作为另一个类型来使用的时候。例如,如果我们希望我们的Stone类型的对象可以在需要的时候自动转换成string来处理,那么我们就实现Stone类的一个转换函数,这个转换函数的函数名就是string,由于该函数的返回类型已经体现在函数名中了,因此不需要写返回值,而且也不需要参数。
- 还有一种转换函数,其实就是构造函数。类的构造函数如果没有声明为explicit,那么编译器可能会在某些时候,自动调用这个构造函数,从而将其他类型的对象转换成该类对象。而如果我们将构造函数声明为explicit,则不会产生这种自动调用,或者说自动转换。为什么要声明为explicit呢?因为正如我们所说的,有两种转换,在某些情形下,这两种转换同时可行的话,可能会导致两种可行的逻辑,这会导致编译器不知如何选择,产生ambiguous错误。
关于虚函数和动态绑定
这个话题内容比较多,我之前也在私下做过一些整理和调研,这里简要概括。
- 在继承关系中,子类是严格继承父类的普通成员函数的。即便子类重写同名函数,产生的效果也只是隐藏了父类的同名函数,并没有事实上覆盖父类同名函数,证据就是,我们还可以通过父类名来调用父类的同名函数。而对于虚函数,子类是通过继承虚函数表来调用虚函数的,因此子类每次重写虚函数,都会对虚函数进行覆盖,被覆盖的虚函数就不复存在了,他们走的路线不同。当然,我们似乎也还是可以通过父类名来访问父类虚函数,但是在那种调用中,已经和虚函数没什么关系了。因为调用虚函数实现动态绑定需要同时满足三个要点:指针或引用,up-cast(父类指针指向子类对象),调用的是虚函数。
- 静态绑定就是在编译的时候确定函数地址。call的后面就是一个函数的地址。而动态绑定的call后面不是明确的函数地址,或者说这个函数地址是和一个运行时传入的对象地址紧密关联的。
关于数组和异质数据结构
- 没有学到关于数组的存储位置的话题,基本都是C语言的东西。编译器会对数组的访问进行优化,避免乘法运算。
- 所谓异质数据结构,是相对于数组而言的,因为数组是同质数据结构。包括结构和联合。也都是连续内存。结构中有一个话题是地址对齐,对齐是为了cpu访问内存次数更少。基本原则是:大小为K的元素的起始地址,必须是K的整数倍。这条规则适用于基本类型,结构体成员,以及结构体作为数组的元素的情形。这就导致结构体内部可能需要填充对齐,而结构体本身也可能需要圆整,因为如果不圆整的话,数组中的下一个结构体的起始地址可能就不是整个结构体大小的整数倍了。
不知不觉又写了50分钟,今天所学知识非常基础,明天打算多花点时间整理学习日记。
哦,还看了一点《stl源码剖析》,讲到了GNU和GPL等开放源码的概念,虽然还是不是很理解,但是比其他地方讲的清楚一点。大概就是,最开始,Unix是免费的,而且很牛逼,然后某个公司开始打算对Unix收费,然后大佬Stallman觉得这个公司很缺德,于是创办了GNU计划,GNU既是他的口号,也是他的态度:“GNU is Not Unix!”。 GNU计划诞生了牛逼的东西包括Emacs编辑器,gcc编译器,以及Linux等等,所以linux是免费的。然后讲了一些开源协议。抱歉,我实在是get不到这些开源协议的约束力何在。说什么,你可以卖我的开源软件,但是你必须把我的宣言写在代码声明中,我真的不太懂,虽然我能理解一点开源带来的精神上的快乐,以及那种简单的追求真相,追求先进、进步以及互帮互助,促进全人类高速前进的情怀。但是我实在搞不懂这些计划和Licence的约束力何在,如果没有约束,那他的意义又何在,有点姜太公钓鱼的佛系味道。
后面看了一点空间配置器的东西,表示初次接触,完全get不到,有机会再看吧。
明日目标
- 奇数天看书。把3.10看完。下午直接看第7章链接。起码快速看个两三节吧。我觉得得稍微加速点。
- 看侯捷视频,这两天尽快刷完吧。看完视频再去看primer应该会轻松点。
- 两道算法题。
今天因为公司的事情计划稍微有点被打乱,看的视频和书不是很多,主要是复习了,自己写了一点demo代码对理解也很有帮助,明天继续多敲代码,然后更加专注一点。睡觉,晚安。