近两周学习总结

<1>用了几天把高效c++看了一遍(下面主要整理了自己平时容易遗忘或者没有常用的知识点)
1. c++中的4中强制转换
(1)const_cast
只能对指针或者引用去除或者添加const属性,对于变量直接类型不能使用const_cast;不能用于不同类型之间的转换,只能改变同种类型的const属性。
(2)static_cast
类似于C风格的强制转换。无条件转换,静态类型转换。由较大类型转换为较小类型,如果是隐式的,编译器通常会产生警告,如果我们显示地提供强制类型转换,则可以关闭警告信息。
(3)dynamic_cast
有条件转换,动态类型转换,运行时类型安全检查(转换失败返回NULL): 1. 安全的基类和子类之间转换。 2. 必须要有虚函数。 3. 相同基类不同子类之间的交叉转换。但结果是NULL。
dynamic_cast涉及运行时类型检查
(4)reinterpreter_cast
这种应该就是内存里的数据不变(同一个二进制数),根据转换的类型重新解释,可以把指针转换为整形数,一般比较少见。
2. 析构函数中绝对不要吐出异常
原因:因为析构函数通常干的事情都是清理释放对象持有的资源。如果在析构的过程中发生了异常就可能会导致资源泄露,导致程序出现不明确的行为。
解决方式:
(1)在析构函数中加上异常捕获的代码,析构函数中可能出现异常的部分。当出现异常的时候,使用abort来强迫终止程序,这样可以阻止异常从析构函数中传递出去,如果传递出去可能会导致不明确的行为。也就是说使用abort可以抢先不明确的行为与死地。
(2)在析构函数中捕获异常,但是不强迫终止程序,默默地吞下异常。这种方案可以保证程序能够继续执行,有时候比草率的结束程序要好一些
(3)另外一种方式可以设计一个接口给用户,另外加一个调用标志isused。这个提供给用户的结构实际上可以完成析构清理资源,关闭数据库连接等的操作。用户在他们的代码中可以使用try-catch异常不活的语句来处理这个可能处理异常的部分,如果调用了接口,在接口代码中设置isused=true。并且在析构函数中检查接口是否被调用的标志,如果接口没有被用户显示的调用,在析构函数中就执行那部分可能会出异常的部分,同样,在析构函数中处理的时候也是要加上try-catch来处理异常,防止因为发生异常,传递出去导致程序不明确的行为。
3. 以独立语句将newd对象存储于智能指针内,否则,一旦异常抛出可能导致难以察觉的资源泄漏。
例如:

func(tr1::shared_ptr<Base> ptr(new Base),fun1());

(1)在调用func必须做三件事:调用fun1();执行new Base;调用tr1::shared_ptr构造函数。
(2)c++以什么次序完成上面三件事,弹性很大,只能确定new Base在调用tr1::shared_ptr构造函数之前。
(3)如果按照下列次序:new Base;fun1();调用tr1::shared_ptr构造函数。万一fun1调用导致异常,可能导致资源泄漏。
改为:

tr1::shared_ptr<Base>ptr(new Base);
func(ptr,fun1())。

4.避免遮掩继承而来的名称
名称的遮掩可以分成变量的遮掩与函数的遮掩两类,本质都是名字的查找方式导致的,当编译器要去查找一个名字时,它一旦找到一个相符的名字,就不会再往下去找了,因此遮掩本质上是优先查找哪个名字的问题。
而查找是分作用域的,虽然本条款的命名是打着“继承”的旗子来说的,但我觉得其实与继承并不是很有关系,关键是作用域。
1. inline函数
(1)类似于C中的#define
在C++中,提供了inline函数来代替C中的宏定义。(通常可以使用const来代替单纯变量的宏定义,它可以提供类型检查。对于形似函数的宏,最好改用inline函数来替换宏定义。)
编译器最优化机制通常被设计用来浓缩那些“不含函数调用“的代码,所以当你inline某个函数时,或许编译器就因此有能力对它执行语境相关最优化。
(2)效率问题
inline函数同#define宏定义一样,都是以函数本体做替换,这样做可能增加你的目标码(object code),从而可能造成代码膨胀(代码膨胀会导致额外的换页行为,降低指令高速缓存装置的击中率,带来效率损失)。如果inline函数本体很小,编译器针对“函数本体”所产生的码可能比针对“函数调用”所产生的码可能更小。
(3)是申请,而不是强制,也不一定要带inline。注意,inline只是对编译器的一个申请,不是强制命令。
(4)构造函数和析构函数一般不应该是inline的
(5)对所有的virtual虚函数都不能申请为inline函数
6.绝不重新定义一个继承而来的缺省参数值,因为缺省参数值是静态绑定。而唯一应该覆写的虚函数,却是动态绑定。
7.明智审慎地使用private继承
(1)私有继承意味着根据某物实现出,通常比复合级别低。但当派生类需要访问protected base的成员或要重新定义继承而来的虚函数时,这么设计是合理的。
(2)和复合不同,私有继承可以empty base最优化。这对于空间要求高的开发而言很重要。
8.以前在学校感觉泛型编程这块没掌握牢固,最近又好好巩固了这块的知识
<2>学习了下qt里面的一些知识
9.模态、非模态、半模态对话框
这里写图片描述
这里写图片描述
10.事件过滤器
有时候,对象需要查看、甚至要拦截发送到另外对象的事件。例如,对话框可能想要拦截按键事件,不让别的组件接收到;或者要修改回车键的默认处理。
QObject有一个eventFilter()函数,用于建立事件过滤器。

virtual bool QObject::eventFilter ( QObject * watched, QEvent * event );

事件过滤器:它会检查接收到的事件。如果这个事件是我们感兴趣的类型,就进行我们自己的处理;如果不是,就继续转发。
eventFilter()函数相当于创建了过滤器,然后我们需要安装这个过滤器。安装过滤器需要调用QObject::installEventFilter()函数。

void QObject::installEventFilter ( QObject * filterObj )

这个函数接受一个QObject *类型的参数。我们可以向一个对象上面安装多个事件处理器,只要调用多次installEventFilter()函数。如果一个对象存在多个事件过滤器,那么,最后一个安装的会第一个执行,也就是后进先执行的顺序。
事件过滤器的强大之处在于,我们可以为整个应用程序添加一个事件过滤器。installEventFilter()函数是QObject的函数,QApplication或者QCoreApplication对象都是QObject的子类,因此,我们可以向QApplication或者QCoreApplication添加事件过滤器。这种全局的事件过滤器将会在所有其它特性对象的事件过滤器之前调用。尽管很强大,但这种行为会严重降低整个应用程序的事件分发效率。因此,除非是不得不使用的情况,否则的话我们不应该这么做。

注意,如果你在事件过滤器中 delete 了某个接收组件,务必将函数返回值设为 true。否则,Qt 还是会将事件分发给这个接收组件,从而导致程序崩溃。
事件过滤器和被安装过滤器的组件必须在同一线程,否则,过滤器将不起作用。另外,如果在安装过滤器之后,这两个组件到了不同的线程,那么,只有等到二者重新回到同一线程的时候过滤器才会有效
11.菜单栏、工具栏和状态栏
在实际开发过程中,QMainWindow通常只作为“主窗口”,对话框窗口则更多地使用QDialog类。QDialog类会缺少一些QMainWindow类提供方便的函数,比如menuBar()以及toolBar()。
(1)使用menuBar()函数创建了一个菜单栏。menuBar()是QMainWindow提供的函数,这个函数会返回窗口的菜单栏,如果没有菜单栏则会新创建一个。
(2)使用的是addToolBar()函数添加新的工具栏。
(3)statusBar()函数添加一个状态栏。
12.布局管理器
所谓 GUI 界面,归根结底,就是一堆组件的叠加。我们创建一个窗口,把按钮放上面,把图标放上面,这样就成了一个界面。在放置时,组件的位置尤其重要。我们必须要指定组件放在哪里,以便窗口能够按照我们需要的方式进行渲染。这就涉及到组件定位的机制。Qt 提供了两种组件定位机制:绝对定位和布局定位。
绝对定位:就是一种最原始的定位方法,给出这个组件的座标和长宽值。
<3>没事的时候会在牛客网上找点编程题做做,锻炼自己的代码逻辑,公司的代码也在看
未来两周计划:
继续学习网络、操作系统方面的知识,看看前端的知识。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章