读书---C++程序设计》[任化敏]

 

前言

这本讲C++的书很薄,但基础知识点都覆盖到了,因为讲得浅显,所以很适合入门选看。这本书有一个特点,就是书中所有的例子都是围绕一个学生管理系统展开的,最后一章还教怎么通过MFCODBC建立一个完整的学生管理系统,全书例子和练习可以说是循序渐进,有助于初学者形成系统工程开发的意识。一句话,初学者可以通过这本书入门,特别是根据作者的例子一个一个实践,会有很大收获;而对C++熟练的人也可以花两三天看完这本书,也可以总结出一些知识点。

 

一. 语言基础

1. 计算机语言发展:机器语言,汇编语言,高级语言; 

2. C++特点:面向对象,支持封装、继承、多态;

3. 程序实现过程:编辑----编译----连接---可执行

4. 字符型数据在内存中是以ASCII码的形式存储的,与整型数据想似,所以字符型数据可以用在数值表达式中;

5. 运算符:算术,赋值,关系,逻辑,位,自增/减,条件,逗号;

6. Break语句用于终止当前循环语句,跳出当前循环结构,使程序执行该循环体外的语句;

7. Continue语句用于循环结构中,结束本次循环,执行下一次循环;

8. C++标准模板库结构

 

9. String库用于处理文本数据;

10. Vector在一个线性列表中存储数据,并按存储的先后顺序进行排列,支持动态的增长和缩减,可以对数据进行访问和增删操作。

11. 内存泄露:当我们不再需要动态分配某个变量时,用delete将其占用的空间释放到自由存储器中,这样能确保这块内存以后可以被另一个变量使用。如果不使用delete,而之后却在指针中使用一个不同的地址值,那么将无法再释放这块内存,也无法使用该内存存储的变量,因为已经失去了访问这个地址的途径。相当于你从银行贷了100亿,现在银行只剩1块钱了,按理要等你还了这100亿银行才有钱贷给其他人,可要是你光知道借钱不知道还钱,那银行就再也没有钱借给别人了,这时候银行唯一有条路走,那就是破产,想想08年的华尔街金融危机就知道了-------这里银行就是计算机,钱就是计算机内存资源,而你就是应用程序;

12. 值传递:函数把实参的一个副本存储到对应的形参当中参与调用函数运算,不能改变实参的值;

13. 指针传递:指针作为函数参数时,形参和实参共同指向某个变量的地址,函数调用时操作的是该地址里的数据,因此能改变实参值;

14. 引用传参:引用作为参数和指针一样,都是把变量的地址传到函数中去,函数调用也是在该地址中操作,也能改变实参。和指针不同的是引用相当于变量别名,但不占用临时空间,且引用经过初始化后一直绑定在对应的变量上,直到生存期结束;

15. 指针作为函数返回值:实际是将一个地址返回给调用,这类函数叫做指针函数;

 

 

[cpp] 
 
  1. #include<iostream>  
  2. using namespace std;  
  3. int *max(int b[10])  
  4. {  
  5.     int *m, j, t;  
  6.     ...  
  7.     return m;  
  8. }    
  9. int main()  
  10. {  
  11.     int a[10];  
  12.     int *p;  
  13.     ...  
  14.     p=max(a);  
  15.     return 0;  
  16. }  

 

16. 引用作为函数返回值:此时函数返回的不是值而是某个变量或对象的引用,所以return后面应该是变量名。且这个变量不能是函数中的局部变量,因为函数在调用结束后会释放掉局部变量,所以被引用的变量或对象应该是全局的或者静态的。

 

[cpp] 
 
  1. #include<iostream>  
  2. using namespace std;  
  3. int &max(int &a, int &b)  
  4. {  
  5.     static int y;  
  6.     ...   
  7.     return y;  
  8. }  
  9. int main()  
  10. {  
  11.     int ave, ave1, ave2;  
  12.     ave=max(ave1, ave2);  
  13.     return 0;  
  14. }  

 

17. 变量有四种存储类型:autostaticexternregister

18. 变量为static时,编译器在内存的静态存储区为其分配存储空间。如果在函数内部定义的局部变量在函数执行过程中被多次调用,并且变量的值需要在下次调用的时候使用,那么这个变量应该被定义为静态的局部变量。使用关键字static说明的全局变量是一个文件内部的全局变量,只能被定义它的源文件使用,同一个程序中的其他源文件中的函数是不能访问这个全局变量的。

19. I/O stream层次结构

 

20. 四个标准输入输出流对象:cincoutcerrclog

21. C++编译系统提供的三种编译预处理功能:宏定义,文件包含和条件编译;

22. 异常捕捉:trycatch都是程序块,需要用{}包含,且二者是一个整体,中间不能包含其他程序块;在try-catch结构中,只能有一个try块,但可以有多个catch块,throw语句可以与try-catch结构处于同一个函数中,也可以不在一个函数中。Throw抛出异常信息后先在本函数中找与之匹配的catch块,没找到就转到上一层函数中处理,若始终找不到匹配的catch块,则系统调用terminate(),终止程序运行;

 

二. 面向对象

 

23. 类是用户自定义的数据类型,对象是类定义的变量,说白了,类就是数据类型,只是它是一种比较高级的数据类型,之所以说高级是因为类是对现实生活的数据抽象-------能够轻松地实现对现实生活中一些事物的仿真,即一个类(或者通过继承、多态机制)可以完整地形容一些事物的属性和行为。而对象呢,联想下这个定义 int i;其中int叫×××数据类型,i叫一个整型变量,同理,假设A是一个自定义的类,则A a1;语句中A就叫类数据类型,a1叫一个这个类数据类型的变量。因为类的内部组织复杂,比较高级,所以人们为了区别类所定义的变量,就给这种类型的变量起了个“实例”或者“对象”的名字,在我看来纯属多余,因为初学者看到“类”“对象”这样的新型名词会感觉是一种新型的知识点一样,很是困惑。总而言之就是一句话,能简单就简单,所以这里总结下来就是两句话:类---c++中一种需要用户自定义的数据类型;对象---类定义的变量;记得:int i; A a1;

24. this指针:通常在对象的成员函数中访问该对象的某成员时,只要给出该成员名即可。事实上,在c++中,一个成员函数被调用时,系统自动像他传递一个this指针,通过这个this指针来调用该成员函数,所以可以逆向思维推测下,this指针就是一个指向该对象的一个隐含指针;

25. 初始化与赋值:初始化是指创建变量并给他赋上一个初值,而赋值则是指擦除对象的当前值并用新的值来代替;

26. Inline()函数是为了提高函数调用的效率而引入的,它不在调用时发生转移,而是在编译时将函数体嵌入到每个inline()函数调用处,这样省去了参数传递、系统栈保护与恢复的时间开销;

27. 复制构造函数:有单个形参,该形参是对该类类型的引用,通常用const修饰,当定义一个新对象并用一个同类型的对象对它进行初始化时,将显示地调用复制构造函数。

28. C++两种初始化形式:直接初始化和复制初始化。直接初始化是直接调用与实参匹配的构造函数,复制初始化总是调用复制构造函数。复制初始化首先使用指定构造函数创建一个临时对象,然后用复制构造函数讲那个临时对象复制到正在创建的对象上。

29. 运算符重载:<类型> operator<运算符名称>(形参)

 

 

[cpp] 
 
  1. ...  
  2. ...//通过运算符+的重载实现虚数加法  
  3. #include <iostream>  
  4. using namespace std;  
  5.   
  6. class Complex()  
  7. {  
  8. private:  
  9.     double real, imag;  
  10. public:  
  11.     Complex(){real=0; imag=0;}  
  12.     Complex(double i,double j)  
  13.     {  
  14.         real=i;  
  15.         imag=j;  
  16.     }  
  17.     Complex operator+(Complex &t);  
  18.     void display();  
  19. };  
  20. Complex Complex::operator+(Complex &t)  
  21. {  
  22.     Complex c;   
  23.     c.real=real+t.real;  
  24.     c.imag=imag+t.imag;  
  25.     return c;  
  26. }  
  27.   
  28. int main()  
  29. {  
  30.   ...  
  31.   ...  
  32.     Complex c1(3,4),c2(2,-2);  
  33.     Complex c3;  
  34.     c3=c1+c2;  
  35.   ...  
  36.   ...  
  37. }  

 

30. 类型兼容:指在公有派生前提下,一个派生类对象可以作为基类的对象来使用,类型兼容有时也被称作复制兼容或类型适应。因为一个派生类拥有基类的所有成员,可以被访问的基类成员在派生类中也是存在的,所以从集合上来说可以将一个派生类对象赋值给一个基类对象;

31. 多继承的构造顺序:

调用各基类的构造函数,个基类构造函数调用的顺序按照派生类定义时声明基类的顺序进行,依次从左到右调用各个基类的构造函数;

调用内嵌对象成员的构造函数,成员对象的构造函数调用顺序按照他们在类中定义的顺序依次进行;

调用派生类的构造函数;

32. 虚基类:避免多继承带来的内存消耗和数据冗余,在定义派生类时,在继承的公共基类的类名前加上关键字virtual。构造函数的调用顺序是先调用虚基类的构造函数,在调用非虚基类的构造函数,最后才调用派生类的构造函数;

class 派生类类名:virtual <访问控制>虚基类类名;

33. 虚函数:如果类中一个函数被申明为虚函数,则表示这个成员函数在派生类中可能存在不同的实现方式。 virtual <数据类型函数名(参数){

函数体};

34. 虚析构函数:定义虚析构函数能够通过指针或者引用实现动态联编,以保证基类指针能够调用适当的析构函数,从而实现对不同的对象进行清理工作;

35. 静态多态性:通过函数重载实现。

36. 动态多态性:通过定义虚函数实现,相同的函数原型,不同的实现方式,即“一个接口,多种方法”,基类指针可以指向基类或派生类对象,而调用基类函数派生类成员并不由指针类型决定,而由指针当前指向的对象的类型决定。

 

三. 好习惯

1. 类声明放于头文件中,也可灵活处理,小类可以放于源文件中。代码要规范,边开发边写开发文档;

2. 开发文档要有几个部分:源文件组织形式,代码规范格式,遇到的问题和解决方法;

3. 动多态应用中,派生类中对应也要加上virtual关键字,说明某函数继承自基类虚函数,实现动态联编,代码规范考虑;

4. 数据结构中定义ElemType的重要性,可以实现数据隐藏,还可以通过typedefElemType定义成其他数据类型,甚至是高级数据类型,这样可简单移植到其他程序中使用。例如双向循环链表,平时数据节点类型是int等基础数据类型,而在linux中,任务队列就是一个双向循环链表构成的,每个链表节点的数据元素存储的应该就是某个执行任务的起始地址;

5. 大程序最好设计自己的命名空间,避免不必要的命名污染;

6. For循环用!=作为结束判断标志,多用++i, 少用i++

7. C++中,定义及常量最好置于头文件中,类实现置于专用的源文件中,而在主源文件中,即在main里面实现程序的逻辑设计