您的位置:首页 > 编程语言 > C语言/C++

C++学习杂记

2016-10-16 12:07 155 查看

第一章

绪论

1.1 计算机程序设计语言的发展

1.1.1 机器语言与汇编语言

1.1.2 高级语言

1.1.3 面向对象的语言

1.2 面向对象的方法

1.2.1 面向对象方法的由来

结构化程序设计的思路是:自顶向下、逐步求精;其程序结构是按功能划分为若干个基本模块,这些模块形成一个树状结构;各模块之间的关系尽可能简单,在功能上相对独立;每一模块内部均是由顺序、选择和循环3 种基本结构组成;其模块化实现的具体方法是使用子程序。

面向对象的方法:首先,它将数据及对数据的操作方法放在一起,作为一个相互依存、不可分离的整体一对象。对同类型对象抽象出其共性,形成类。类中的大多数量立据,只能用本类的方法进行处理。类通过一个简单的外部接口与外界发生关系.对象与对象之间通过消息进行通信。

面向对象方法所强调的基本原则,就是直接面对客观存在的事物来进行软件开发,将人们在日常生活中习惯的思维方式和表达方式应用在软件开发中,使软件开发从过分专业化的方法、规则和技巧中回到客观世界,回到人们通常的思维方式。

1.2.2 面向对象的基本概念

1.对象

面向对象方法中的对象,是系统中用来描述客观事物的一个实体,它是用来构成系统的一个基本单位。对象由一组属性和一组行为构成。

2.类

面向对象方法中的”类”,是具有相同属性和服务的一组对象的集合。

3.封装

封装是面向对象方法的一个重要原则,就是把对象的属性和服务结合成一个独立的系统单位,并尽可能隐蔽对象的内部细节

4.继承

特殊类的对象拥有其一般类的全部属性与服务,称做特殊类对一般类的继承。

5.多态

多态性是指在一般类中定义的属性或行为,被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。

1.3面向对象的软件开发

面向对象的软件工程是面向对象方法在软件工程领域的全面应用。它包括面向对象的分析(OOA) 、面向对象的设计(OOD) 、面向对象的编程(OOP) 、面向对象的测试(OOT) 和面向对象的软件维护(OOSM) 等主要内容。

1.3.1分析

1.3.2设计

1.3.3编程

1.3.4测试

1.3.5维护

1.4信息的表示与存储

1.4.1 计算机的数字系统

1.4.2 几种进位记数制之间的转换

1.R进制转换为十进制:

对任意一个R 进制的数X ,其值V(X) 可表示为:

V(X)=∑ni=0XiRi+∑−mi=−1XiRi

2.十进制转换为R进制:

1.十进制整数转换成R进制的整数

除R取余法

2.十进制小数转换成R进制小数

乘R取整法

需要注意的是,十进制小数常常不能准确地换算为等值的二进制小数(或其他R进制数) ,有换算误差存在。

3.二、八、十六进制的相互转换

1.4.3 信息的存储单位

位(bit):量度数据的最小单位,表示1 位二进制信息。

字节(Byte):1K=1024B,1M=1024K,1G=1024M,1T=1024G

字:字是位的组合,并作为一个独立的信息单位处理。字又称为计算机

字,它的含义取决于机器的类型、字长以及使用者的要求。常用的固定字长有8 位、16 位、32 位等。

机器字长:在讨论信息单位时,还有一个与机器硬件指标有关的单位,这就是机器字长。机器字长一般是指参加运算的寄存器所含有的二进制数的位数,它代表了机器的精度,如32 位、64 位等。

1.4.4 二进制数的编码表示

1.原码:“符号-绝对值表示”的编码,称为原码。

对于一个带符号的纯小数,它的原码表示就是把小数点左边一位用作符号位。

2.反码:正数的反码与原码表示相同。

负数反码的符号位与原码相同(仍用1 表示) ,其余各位取反(0 变1. 1 变0)。

3.补码:对于一个负数,其补码由该数反码的最末位加1 求得。

对于正数来说,其原码、反码、补码形式相同。

补码的特点:1.零的表示唯一2.符号位可作为数值参加运算3.补码运算的结果仍为补码

两个正数相加结果可能因为溢出变为负数。

1.4.5定点数和浮点数

1.4.6数值的表示范围

机器中数的表示范围与数据位数及表示方法有关。一个m 位整数(包括一位符号位) ,如果采用原码或反码表示法,能表示的最大数为2m−1-1 ,最小数为-2m−1-1;若用补码表示,能表示的最大数值为2m−1-1 ,最小数为-2m−1。

这里要说明一点,由于补码中”0” 的表示是唯一的,故[X]补= 100 … 0. 对应的真值X=-2m−1,从而使补码的表示范围与原码有一点差异。(注意:补码100…0 的形式是一个特殊的情况,权为2m−1 位的1既代表符号又表示数值)。对补码的表示范围,本书不做证明,读者如果感兴趣,可以自行验证一下。

例如,设m=8 , 则原码表示范围为-127~+127 ,反码的表示范围也是-127 ~+127 ,补码的表示范围是-128~ +127

一个n 位定点小数,小数点左边一位表示数的符号,采用原码或反码表示时,表示范围为(1-2−n)~(1 -2−n); 采用补码表示时,表示范围为-1 ~(1 -2−n) 。

至于浮点数的表示范围,则由阶码位数和尾数位数决定。若阶码用r 位整数(补码)表示,尾数用n 位定点小数(原码)表示,则浮点数范围是:

−(1−2−n)∗22r−1−1−1 ~ +(1−2−n)∗22r−1−1

为了扩大数的表示范围,应该增加阶码的位数,每加一位,数的表示范围就扩大一倍。而要增加精度,就需要增加尾数的位数,在定长机器字中,阶码位数和尾数位数的比例要适当。但为了同时满足对数的范围和精度的要求,往往采用双倍字长甚至更多个字长来表示一个浮点数。

1.4.7非数值信息的表示

1. 5 程序开发的基本概念

1. 5.1 基本术语

1.源程序

2.目标程序

3.翻译程序:翻译程序有三种不同的类型

1).汇编程序:汇编语言—>目标程序

2).编译程序:高级语言—>目标程序

3).解释程序:边翻译边执行高级语言, 解释程序不产生整个的目标程序

typedef:为一个已有的数据类型另外命名 typedef double Area, Volume;

枚举类型:enum GameResult {WIN, LOSE, TIE, CANCEL};

值传递:不改变调用者的值

引用传递:改变调用者的值

内联函数:内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处

需要使用关键字inline


带默认形参值的函数:

1.函数在定义时可以预先声明默认的形参值。

2.调用时如果给出实参,则用实参初始化形参,如果没有给出实参,则采用预先声明的默认形参值。

3.函数在定义时可以预先声明默认的形参值

4.在相同的作用域内,不允许在同一个函数的多个声明中对同一个参数的默认值重复定义,

即使前后定义的值相同也不行

面向对象程序设计的基本特点:抽象、封装、继承、多态。

数据成员和函数成员

构造函数:构造画数的作用就是在对象被创建时利用特定的值构造对象,将对象初始化为一个

特定的状态

复制构造函数:其形参是本类的对象的引用。其作用是使用一个已经存在的对象(由复制构造函数的参数指定)

去初始化同类的一个新对象。

复制构造函数

对象以值传递的方式传入函数参数

对象以值传递的方式从函数返回

对象需要通过另外一个对象进行初始化

析构函数:

1.用来完成对象被删除前的一些清理工作,也就是专门做扫尾工作的。析构函数是在对象的

生存期即将结束的时刻被自动调用的

2.析掏函数不接收任何参数

函数重载:两个以上的函数,具有相同的函数名,但是形参的个数或者类型不同,编译器根据实

参和形参的类型及个数的最佳匹配,自动确定调用哪一个函数,这就是函数的重载。

类的组合:类的组合描述的就是-个类内嵌其他类的对象作为成员的情况,它们之间的关系是

一种包含与被包含的关系。

1.调用内嵌对象的构造函数,调用顺序按照内嵌对象在组合类的定义中出现的次序。

2.执行本类构造函数的函数体。

3.析构函数的调用执行顺序与构造画数刚好相反。

结构体:结构体和类的唯一区别在于,结构体和类具有不同的默认访问控制属性:

在类中,对于未指定访问控制属性的成员,其访问控制属性为私有类型(private) ;

在结构体中,对于未指定任何访问控制属性的成员,其访问控制属性为公有类型(public);

struct Student {

}

联合体:联合体的全部数据成员共享同一组内存单元

union Mark{

char grade;

bool pass;

int percent;

}

1.联合体的各个对象成员,不能有自定义的构造函数、自定义的析构函数和重载的复制赋值运算符,

不仅联合体的对象成员不能有这些函数,这些对象成员的对象成员也不能有,以此类推。

2.联合体不能继承,因而也不支持包含多态。

前向引用声明

类型转换:1.static_cast 2.const_cast 3.dynamic_cast 4.reinterpret_cast.

对象的生存期:静态生存期、动态生存期

友元函数:

友元类:若A类为B类的友元类,则A类的所有成员函数都是B类的友元函数,都可以访问B类的私有和保护成员

常对象:常对象必须进行初始化,而且不能被更新

1.如果将一个对象说明为常对象,则通过该常对象只能调用它的常成员函数,而不能调用其他成员函数

常数据成员:任何函数中都不能对该成员赋值。构造函数对该数据成员进行初始化,就只能通过初始化列表

常引用:常引用所引用的对象不能被更新

数组的存储:数组元素在内存中是顺序、连续存储

数组的初始化:数组的初始化就是在声明数组时给部分或全部元素赋初值

数组作为函数参数:使用数组名传递数据时,传递的是地址

mutable

指针:指针也是→种数据类型,具有指针类型的变量称为指针变量。指针变量是用于存放内存单元地址的。

数组名称实际上就是一个不能被赋值的指针,即指针常量

指针注意的几点:

1.可以声明指向常量的指针,此时不能通过指针来改变所指对象的值,但指针本身可以改变,可以指向另外的对象

2.可以声明指针类型的常量,这时指针本身的值不能被改变

3.一般情况下,指针的值只能赋给相同类型的指针。但是有一种特殊的void类型指针,

可以存储任何类型的对象地址,就是说任何类型的指针都可以赋值给void类型的指针变量。

经过使用类型显式转换,通过void类型的指针便可以访问任何类型的数据。

指针型函数:当一个函数的返回值是指针类型时,这个函数就是指针型函数。

1.格式:数据类型 *函数名(参数表){函数体}

指向函数的指针:可以像使用函数名一样使用指向函数的指针来调用函数。

1.格式:数据类型( *头函数指针名)(形参表)

对象指针:类名 *对象指针名;

访问对象成员:对象指针名->成员名

this指针:

指向数据成员的指针:

类型说明符 类名:: *指针名;

对数据成员指针赋值的一般语法:指针名=&类名::数据成员名

访问数据成员:对象名.类成员指针名 或者 对象指针名->类成员指针名

指向函数成员的指针:

类型说明符(类名:: *指针名)(参数表);

对成员函数指针赋值的一般语法:指针名=&类名::函数成员名;

调用成员函数:(对象名.*类成员指针名)(参数表)

assert宏的原型定义在

vector不是一个类,而是一个类模板vector<元素类型〉数组对象名(数组长度);

与普通数组不同的是,用vector定义的数组对象的所有元素都会被初始化。

如采数组的元素类型为基本数据类型,则所有元素都会被以0

初始化;如果数纽元素为类类型,则会调用类的默认构造函数初始化。

因此如果以此形式定义的vector动态数组,需要保证作为数纽元素的类具有默认构造函数。

另外,初值也可以自己指定,但只能为所有元素指定相同初值,形式为:

vector<元素类型〉数组对象名(数组长度,元素初值);

String类:append 追加,assign 赋值 insert,compare,substr,find,swap

派生类生成过程:1.吸收基类成员2.改造基类成员3.添加新的成员

派生类构造函数:

1.如果对基类初始化时,需要调用基类的带有形参表的构造函数时,派生类就必须声明构造函数

2.派生类构造函数执行的一般次序如下。

1).调用基类构造函数,调用顺序按照它们被继承时声明的顺序(从左向右)。

2).对派生类新增的成员对象初始化,调用顺序按照它们在类中声明的顺序。

3).执行派生类的构造函数体中的内容。

派生类的复制构造函数:Derived: :Derived(const Derived &v) : Base (v) {…}

派生类的析构函数:与构造函数执行时完全相反。

1.如果某派生类的多个基类拥有同名的成员,同时派生类又新增这样的同名成员,

在这种情况下,派生类成员将隐藏所有基类的同名成员

1.虚基类的声明是在派生类的定义过程中进行的,其语法形式为

class派生类名:virtual继承方式 基类名

2.将共同基类设置为虚基类,这时从不同的路径继承过来的同名数据成员在内存中就只有一个副本,

同一个函数名也只有一个映射。

虚基类及其派生类构造函数:如果虚基类声明有非默认形式的(即带形参的)构造

函数,并且没有声明默认形式的构造函数。这时,在整个继承关系中,直接或间

接继承虚基类的所有派生类,都必须在构造函数的成员初始化表中列出对虚基类的初始化

operator:是定义运算符重载函数的关键字

返回类型 operator 运算符 (形参表){ 函数体 }

对于前置单目运算符,重载函数没有形参,对于后置单目运算符,重载函数有一个int型形参。

虚函数:

1.虚函数是动态绑定的基础。虚函数必须是非静态的成员函数。虚函数经过派生之

后,在类族中就可以实现运行过程中的多态。

2.一般虚函数成员的声明语法是:virtual 函数类型 函数名(形参表);

虚析构函数:如果一个类的析构函数是虚函数,那么由它派生而来的所有子类的析构函数也是虚析构函数

抽象类:带有纯虚函数的类是抽象类,抽象类不能实例化

多态分两种:

重载,是一个类中多态性的体现

重写,是父子类中多态性的体现

方法重写是因为原有的方法不能满足要求,需要增加或修改新的功能

排序算法

插入排序:直接插入排序、折半插入排序、希尔排序

交换排序:冒泡排序、快速排序

选择排序:直接选择排序、堆排序

归并排序

分配排序:基数排序、箱排序

直接插入排序:首先在当前有序区R[1..i-1]中查找R[i]的正确插入位置k(1≤k≤i-1);

然后将R[k..i-1]中的记录均后移一个位置,腾出k位置上的空间插入R[i]。


折半插入排序:由于前半部分为已排好序的数列,这样我们不用按顺序依次寻找插入点,

可以采用折半查找的方法来加快寻找插入点的速度。


希尔排序:希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;

随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,
算法便终止。


冒泡排序:它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。

走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。


快速排序:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的

所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,
以此达到整个数据变成有序序列。


堆排序:可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。

大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。
在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。


直接选择排序:第一次从R[0]~R[n-1]中选取最小值,与R[0]交换,第二次从R[1]~R[n-1]中选取最小值,

与R[1]交换,….,第i次从R[i-1]~R[n-1]中选取最小值,与R[i-1]交换,…..,

第n-1次从R[n-2]~R[n-1]中选取最小值,与R[n-2]交换,总共通过n-1次,

得到一个按排序码从小到大排列的有序序列·

搜索算法

二分查找:将n个元素分成大致相等的两部分,取a[n/2]与x做比较,如果x=a[n/2],则找到x,算法中止;

如果x

深度优先搜索:

深度优先搜索用栈(stack)来实现,整个过程可以想象成一个倒立的树形:

1、把根节点压入栈中。

2、每次从栈中弹出一个元素,搜索所有在它下一级的元素,把这些元素压入栈中。

并把这个元素记为它下一级元素的前驱。

3、找到所要找的元素时结束程序。

4、如果遍历整个树还没有找到,结束程序。

广度优先搜索:

广度优先搜索使用队列(queue)来实现,整个过程也可以看做一个倒立的树形:

1、把根节点放到队列的末尾。

2、每次从队列的头部取出一个元素,查看这个元素所有的下一级元素,把它们放到队列的末尾。

并把这个元素记为它下一级元素的前驱。

3、找到所要找的元素时结束程序。

4、如果遍历整个树还没有找到,结束程序。

基本算法思想:1.回溯 2.递归 3.贪心 4.动态规划 5.分治

1.回溯:1)针对所给问题,定义问题的解空间,它至少包含问题的一个(最优)解。

2)确定易于搜索的解空间结构,使得能用回溯法方便地搜索整个解空间 。

3)以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索。

2.递归:程序调用自身的编程技巧称为递归

3.贪心:

4.动态规划:

5.分治:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  面向对象