1、  在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少 CPU 跨切循环层的次数。

2、  如果循环体内存在逻辑判断,并且循环次数很大,宜将逻辑判断移到循环体的外面。

3、  即使程序真的不需要default 处理,也应该保留语句 default : break。

4、  C 语言用#define
来定义常量(称为宏常量)。 C++
语言除了 #define
外还可以用 const 来定义常量(称为 const
常量)。

5、  const 与 #define 的比较

Ø  const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误(边际效应)。

Ø  有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。

6、  需要对外公开的常量放在头文件中,不需要对外公开的常量放在定义文件的头部。为便于管理,可以把不同模块的常量集中存放在一个公共的头文件中。

7、  const 数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的,因为类可以创建多个对象,不同的对象其 const 数据成员的值可以不同。

8、  不能在类声明中初始化const 数据成员。以下用法是错误的,因为类的对象未被创建时,编译器不知道 SIZE 的值是什么。

class A

{…

const intSIZE = 100; // 错误,企图在类声明中初始化 const 数据成员

intarray[SIZE]; // 错误,未知的 SIZE

};

9、  const 数据成员的初始化只能在类构造函数的初始化表中进行。

10、             枚举常量不会占用对象的存储空间,它们在编译时被全部求值。枚举常量的缺点是:它的隐含数据类型是整数,其最大值有限,且不能表示浮点数(如 PI=3.14159)。

11、             一般地,应将目的参数放在前面,源参数放在后面。

12、             有时候函数原本不需要返回值,但为了增加灵活性如支持链式表达,可以附加返回值。

13、             很多程序错误是由非法参数引起的,我们应该充分理解并正确使用“断言”( assert)来防止此类错误。

14、             return 语句不可返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数体结束时被自动销毁。

15、             断言 assert 是仅在 Debug 版本起作用的宏,它用于检查“不应该”发生的情况。

16、             引用的一些规则如下:

Ø  引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。

Ø  不能有 NULL 引用,引用必须与合法的存储单元关联(指针则可以是 NULL)。

Ø  一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。

17、             内存分配方式有三种:

Ø  从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量, static 变量。

Ø  在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

Ø  从堆上分配,亦称动态内存分配。程序在运行的时候用 malloc 或 new 申请任意多少的内存,程序员自己负责在何时用 free 或 delete 释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

18、             常见的内存错误及其对策如下:

Ø  内存分配未成功,却使用了它。

Ø  内存分配虽然成功,但是尚未初始化就引用它。

Ø  内存分配成功并且已经初始化,但操作越过了内存的边界。

Ø  忘记了释放内存,造成内存泄露。

Ø  释放了内存却继续使用它。(使用 free 或 delete 释放了内存后,没有将指针设置为 NULL。导致产生“野指针”。)

19、             数组名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。

20、             不能对数组名进行直接复制与比较。

21、             用运算符 sizeof 可以计算出数组的容量(字节数)。sizeof(p)得到的是一个指针变量的字节数,相当于 sizeof(char*),而不是 p 所指的内存容量。 C++/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。

22、             注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。

23、             如果函数的参数是一个指针,不要指望用该指针去申请动态内存。(可以用指针的指针)

24、             发现指针 p 被 free 以后其地址仍然不变(非 NULL),只是该地址对应的内存是垃圾, p 成了“野指针”。如果此时不把 p 设置为 NULL,会让人误以为 p 是个合法的指针。

25、             free()之后由于指针所指向的内存已经被释放,所以其它代码有机会改写其中的内容,相当于该指针从此指向了自己无法控制的地方,也称为野指针。

26、             我们发现指针有一些“似是而非”的特征:

Ø  指针消亡了,并不表示它所指的内存会被自动释放。

Ø  内存被释放了,并不表示指针会消亡或者成了 NULL 指针。

27、             “野指针”的成因主要有两种:

Ø  指针变量没有被初始化。任何指针变量刚被创建时不会自动成为 NULL 指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为 NULL,要么让它指向合法的内存。

Ø  指针 p 被 free 或者 delete 之后,没有置为 NULL,让人误以为 p 是个合法的指针。

Ø  指针操作超越了变量的作用范围。

28、             malloc 与 free 是 C++/C 语言的标准库函数,new/delete 是 C++的运算符。它们都可用于申请动态内存和释放内存。

29、             对于非内部数据类型的对象而言,光用 maloc/free 无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free 是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于 malloc/free。因此 C++语言需要一个能完成动态内存分配和初始化工作的运算符 new,以及一个能完成清理与释放内存工作的运算符 delete。注意 new/delete 不是库函数。

30、             由于内部数据类型的“对象”没有构造与析构的过程,对它们而言 malloc/free 和new/delete 是等价的。

31、             如果用 free 释放“ new 创建的动态对象”,那么该对象因无法执行析构函数而可能导致程序出错。如果用 delete 释放“ malloc 申请的动态内存”,理论上讲程序不会出错,但是该程序的可读性很差。所以 new/delete 必须配对使用, malloc/free 也一样。

32、             malloc/free 的使用我们应当把注意力集中在两个要素上:“类型转换”和“ sizeof”。

Ø  malloc 返回值的类型是 void *,所以在调用 malloc 时要显式地进行类型转换,将 void * 转换成所需要的指针类型。

Ø  malloc 函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数。

33、             如果 p 是 NULL 指针,那么 free 对 p 无论操作多少次都不会出问题。如果 p 不是 NULL 指针,那么 free 对 p连续操作两次就会导致程序运行错误。

34、             如果用 new
创建对象数组,那么只能使用对象的无参数构造函数。例如

Obj *objects = newObj[100]; // 创建100
个动态对象不能写成

Obj *objects = newObj[100](1);// 创建100

在用delete 释放对象数组时,留意不要丢了符号‘ []’。例如

delete []objects; // 正确的用法

delete objects; // 错误的用法

后者相当于delete objects[0],漏掉了另外 99
个对象。

35、             c++中为什么static成员函数不能声明为const?(注意是成员函数)

答:这是C++的规则,const修饰符用于表示函数不能修改成员变量的值,该函数必须是含有this指针的类成员函数,函数调用方式为thiscall,而类中的static函数本质上是全局函数,调用规约是__cdecl或__stdcall,不能用const来修饰它。

36、             重载和内联机制既可用于全局函数也可用于类的成员函数, const 与virtual 机制仅用于类的成员函数。

37、             只能靠参数而不能靠返回值类型的不同来区分重载函数。

38、             注意并不是两个函数的名字相同就能构成重载。全局函数和类的成员函数同名不算重载,因为函数的作用域不同。

39、             当心隐式类型转换导致重载函数产生二义性。

40、             成员函数被重载的特征:

Ø  相同的范围(在同一个类中);

Ø  函数名字相同;

Ø  参数不同;

Ø  virtual 关键字可有可无。

41、             覆盖是指派生类函数覆盖基类函数,特征是:

Ø  不同的范围(分别位于派生类与基类);

Ø  函数名字相同;

Ø  参数相同;

Ø  基类函数必须有virtual 关键字。

42、             “隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:

Ø  如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无 virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。【参数不同一定会被隐藏】

Ø  如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有 virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。【没有virtual一定会被隐藏】

43、             参数缺省值只能出现在函数的声明中,而不能出现在定义体中。

44、             如果函数有多个参数,参数只能从后向前挨个儿缺省,否则将导致函数调用语句怪模怪样。

45、             在 C++运算符集合中,有一些运算符是不允许被重载的。这种限制是出于安全方面的考虑,可防止错误和混乱。

Ø  不能改变 C++内部数据类型(如int,float 等)的运算符。

Ø  不能重载‘ .’,因为‘ .’在类中对任何成员都有意义,已经成为标准用法。

Ø  不能重载目前 C++运算符集合中没有的符号,如#,@,$等。原因有两点,一是难以理解,二是难以确定优先级。

Ø  对已经存在的运算符进行重载时,不能改变优先级规则,否则将引起混乱。

46、             在 C 程序中,可以用宏代码提高执行效率。宏代码本身不是函数,但使用起来象函数。预处理器用复制宏代码的方式代替函数调用,省去了参数压栈、生成汇编语言的 CALL调用、返回参数、执行 return 等过程,从而提高了速度。使用宏代码最大的缺点是容易出错,预处理器在复制宏代码时常常产生意想不到的边际效应。使用宏代码还有另一种缺点:无法操作类的私有数据成员。

47、             C++ 语言的函数内联机制既具备宏代码的效率,又增加了安全性,而且可以自由操作类的数据成员。所以在 C++ 程序中,应该用内联函数取代所有宏代码。

48、             关键字 inline
必须与函数定义体放在一起才能使函数成为内联,仅将 inline
放在函数声明前面不起任何作用。

49、             定义在类声明之中的成员函数将自动地成为内联函数。

50、             内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。

51、             以下情况不宜使用内联:

Ø  如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。

Ø  如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。

52、             每个类只有一个析构函数和一个赋值函数,但可以有多个构造函数(包含一个拷贝构造函数,其它的称为普通构造函数)。对于任意一个类 A,如果不想编写上述函数,C++编译器将自动为 A 产生四个缺省的函数,如:

Ø  A(void);                                          //缺省的无参数构造函数

Ø  A(const A &a);                             //缺省的拷贝构造函数

Ø  ~A(void);                                       //缺省的析构函数

Ø  A & operate =(const A &a);     //缺省的赋值函数

53、             构造函数与析构函数的另一个特别之处是没有返回值类型,这与返回值类型为 void 的函数不同。

54、             构造函数有个特殊的初始化方式叫“初始化表达式表”(简称初始化表)。初始化表位于函数参数表之后,却在函数体 {} 之前。这说明该表里的初始化工作发生在函数体内的任何代码被执行之前。

55、             类的 const 常量只能在初始化表里被初始化,因为它不能在函数体内用赋值的方式来初始化。

56、             类的数据成员的初始化可以采用初始化表或函数体内赋值两种方式,这两种方的效率不完全相同。

57、             非内部数据类型的成员对象应当采用第一种方式初始化,以获取更高的效率。

58、             构造和析构的次序:构造从类层次的最根处开始,在每一层中,首先调用基类的构造函数,然后调用成员对象的构造函数。析构则严格按照与构造相反的次序执行,该次序是唯一的,否则编译器将无法自动执行析构过程。

59、             成员对象初始化的次序完全不受它们在初始化表中次序的影响,只由成员对象在类中声明的次序决定。这是因为类的声明是唯一的,而类的构造函数可以有多个,因此会有多个不同次序的初始化表。如果成员对象按照初始化表的次序进行构造,这将导致析构函数无法得到唯一的逆序。

60、             拷贝构造函数是在对象被创建时调用的,而赋值函数只能被已经存在了的对象调用。

61、             深度复制(针对《c++ primer plus》一书string例题的解释):复制构造函数应当复制字符串并将副本的地址赋给str成员,而不仅仅是复制字符串的地址,这样每个对象都有自己的字符串,而不是引用另一个对象的字符串,调用析构函数时都将释放不同的字符串,而不会试图去释放已经被释放的字符串。

62、             何时调用复制构造函数:新建一个对象并将其初始化为同类现有对象时,复制构造函数都将被调用。每当程序生成了对象副本时,编译器都将使用复制构造函数。具体的说,当函数按值传递对象或函数返回对象时,都将使用复制构造函数。记住,按值传递意味着创建原始变量的一个副本。编译器生成临时对象时,也将使用复制构造函数。何时生成临时对象随编译器而异,但无论那种编译器,当按值传递和返回对象时,都将调用复制构造函数。

63、             String类的赋值函数要做的工作:

Ø  自我检查赋值的情况

Ø  释放成员指针以前指向的内存

Ø  复制数据而不仅仅是数据的地址

Ø  指向一个返回对象的引用(不要将 return *this 错写成 return this)

64、             基类与派生类的析构函数应该为虚(即加 virtual关键字)。

#include <iostream.h>

classBase

{

public:

virtual ~Base() { cout<< "~Base" << endl ; }

};

classDerived : public Base

{

public:

virtual ~Derived() { cout<< "~Derived" << endl; }

};

voidmain(void)

{

Base * pB = new Derived; // upcast

delete pB;

}

输出结果为:

~Derived

~Base

如果析构函数不为虚,那么输出结果为

~Base

65、             如果使用指向对象的引用或指针来调用虚方法,程序将使用为对象类型定义的方法,而不使用为引用或指针类型定义的方法。这称为动态联编或晚期联编。这种行为非常重要,因为这样基类指针或引用可以指向派生类对象。

66、             用 const
修饰函数的参数:
如果参数作输出用,不论它是什么数据类型,也不论它采用“指针传递”还是“引用传递”,都不能加 const
修饰,否则该参数将失去输出功能。const
只能修饰输入参数。(参数做输出用不能加const,const只能修饰输入参数)

67、             如果输入参数采用“值传递”,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加 const
修饰。

68、             const 成员函数的声明看起来怪怪的: const 关键字只能放在函数声明的尾部,大概是因为其它地方都已经被占用了。

高质量C++C编程指南笔记 标签: c++笔记 2015-11-22 20:59 179人阅读 评论(0) 收藏的更多相关文章

  1. 苹果应用商店AppStore审核中文指南 分类: ios相关 app相关 2015-07-27 15:33 84人阅读 评论(0) 收藏

    目录 1. 条款与条件 2. 功能 3. 元数据.评级与排名 4. 位置 5. 推送通知 6. 游戏中心 7. 广告 8. 商标与商业外观 9. 媒体内容 10. 用户界面 11. 购买与货币 12. ...

  2. 【搜索引擎Jediael开发笔记】v0.1完整代码 2014-05-26 15:17 463人阅读 评论(0) 收藏

    详细代码请见 E:\Project\[重要]归档代码\SearchEngine归档代码 或 https://code.csdn.net/jediael_lu/jediael/tree/10991c83 ...

  3. 【搜索引擎Jediael开发笔记】V0.1完整代码 2014-05-26 15:16 443人阅读 评论(0) 收藏

    详细代码请见 E:\Project\[重要]归档代码\SearchEngine归档代码 或 https://code.csdn.net/jediael_lu/jediael/tree/10991c83 ...

  4. 提高编程能力的7条建议 分类: T_TALENT 2014-04-12 10:41 294人阅读 评论(0) 收藏

    编程是非常酷的一件事情,但是在酷炫的背后它对很多人来说还是挺难的.很多人在学习编程之初就被困难击败了. 当你不熟悉编程的时候,你可能会觉得无从下手,并且不知道如何运用学到的知识.只要你通过了这一困难的 ...

  5. Shell脚本编程入门(一) 分类: 学习笔记 linux ubuntu 2015-07-09 21:06 29人阅读 评论(0) 收藏

    最近在学shell,记录一下. if语句的使用: 1.判断两个参数大小 #!/bin/sh #a test about if statement a=10 b=20 if [ $a -eq $b ]; ...

  6. js笔记 标签: javascript 2016-08-01 13:30 75人阅读 评论(0) 收藏

    typeof可以用来检测给定变量的数据类型,typeof是一个操作符而不是函数,所以圆括号可以省略. Undefined类型只有一个值,即特殊的undefined.在使用var声明变量但未对其加以初始 ...

  7. Latex笔记(参考文献) 分类: LaTex 2014-11-08 17:41 239人阅读 评论(0) 收藏

    当你用LaTeX来写文档,在管理参考文献时,你可能会用到bibtex, 也许你会嫌麻烦,会选择用 \begin{thebibliography}{10} \bibitem xxxx \bibitem ...

  8. shell入门之函数应用 分类: 学习笔记 linux ubuntu 2015-07-10 21:48 77人阅读 评论(0) 收藏

    最近在学习shell编程,文中若有错误的地方还望各位批评指正. 先来看一个简单的求和函数 #!/bin/bash #a test about function f_sum 7 8 function f ...

  9. Eclipse和MyEclipse的区别 分类: 编程工具 2015-07-18 11:12 23人阅读 评论(0) 收藏

    今天,在一个Q群里有人问Eclipse和MyEclipse的区别.虽然对于知道的人来说答案很简单,但是对于不知道的人来说就很难,很多问题也都是这样的,会者不难,难者不会. 其实,网上搜搜答案就挺多的, ...

随机推荐

  1. 百度ECharts数据绑定诀窍

    百度Echarts的功能还是蛮好用的.. 不能说多好但是也不次.. 下边就分享一些数据绑定经验..对在处理过程中的思路有一些帮助... 报表里用的最多的可以说是 饼状图和柱形图.. 饼状图里当然是包括 ...

  2. HttpUtils 封装类

    作为一个web开发人员,对Http 请求,并不陌生.有时候,我们请求的时候,需要使用代码实现,一般情况,我们使用Apache Jakarta Common 下的子项目.的HttpClient. 可是我 ...

  3. 【Nginx】关于域名转发proxy_pass

    在配置nginx的时候,有一个需求,访问m.XXX.com的时候,需要实际访问www.YYY.com/m,并且域名不能发生变化. 达成这个需求有两种做法: 第一种就是301跳转,使用rewrite来跳 ...

  4. 大数据技术之_16_Scala学习_13_Scala语言的数据结构和算法_Scala学习之旅收官之作

    第十九章 Scala语言的数据结构和算法19.1 数据结构(算法)的介绍19.2 看几个实际编程中遇到的问题19.2.1 一个五子棋程序19.2.2 约瑟夫问题(丢手帕问题)19.2.3 其它常见算法 ...

  5. Winform取消用户按下键盘的事件

    1. 有时候针对某个控件,想取消它的所有键盘按下事件, 只需要为这个控件绑定keyDown事件即可,然后处理的代码如下: private void txtDeviceName_KeyDown(obje ...

  6. 跨域拦截Access-Control-Allow-Origin设置多个origin

    在Extjs和java项目碰到了需要同时处理跨域,外部要访问后台接口的问题 原来的代码是这样,只能设置一个extjs前台需要过滤的跨域请求 package com.xgt.config; import ...

  7. 【转】HttpWebRequest 保持session

    通过HttpWebRequest获取网页内容并保持session,最主要的就是存储cookie.这里使用了一个静态变量m_Cookie用来存储cookie的内容.第二次请求网页的时候把cookie传送 ...

  8. vs2013中$(TargetPath)与Link.OutputFile不同,导致调试debug找不到exe

    之前把VS2008项目升级为VS2013项目后,出现了VS2013调试debug找不到exe文件的现象,如:http://blog.sina.com.cn/s/blog_6c617ee301013xt ...

  9. Centos 从零开始 (三)

    8:连接阿里云. 需要用到 ssh指令进行远程登陆 [root@localhost ~]# service sshd start #如果没开启服务的话,需要开启服务. [root@localhost  ...

  10. Linux文件上传下载sz 和 rz 命令

    windows系统和linux系统之间文件上传和下载用到 rz 和 sz 命令.rz: 上传文件sz:下载文件 先检查是否安装rz,sz模块 安装rz,sz 模块yum search sz安装yum ...