导图社区 C 程序设计完美基础
c 所有入门知识点都在上面,全部理解完全可以通过大学考试
编辑于2020-07-24 18:13:34《C++面向对象程序设计》
第二章C++基础知识
变量与赋值
变量中容纳的数字或其他类型的的数据称为这个变量的值
TIPS:应坚持使用有意义的名称作为变量名,最好使用小写
标识符就是变量的名称,以字母或者下划线开头
预定义标识符 main cout ...
特殊的标识符 关键字/保留字
变量声明就是向编译器说明 1分配多大内存位置 2:拥哪种编码方式将变量值变为0/1
输入与输出
<<插入操作符
\n换行符
预编译指令
include预编译指令
using预编译指令
命名空间
用来将所有C++名称规范划分到不同集合(即命名空间)
转义序列
转义序列由两个字符构成且两字符间没有空格
用\来转义
\\来表示\的本身,而不是一个转义序列
\"表明需要一个真正的双引号,而不是结束一个字符串常量
格式化带小数点的数字
cout.setf(ios::fixed) ;
cout.setf(ios::showpoint);
cout.precision(2);
数据类型和表达式
因为double类型计算机将其保存为近似值,所以如果某变量的值肯定是一个整数,最好直接声明为int类型
科学计数法/浮点计数法
e计数法
3.67e-6
正负号指出小数点移动方向,正号为向右移动
数字指出移动几位
double类型的最大值大于int类型
float单精度类型,内存占用是double双精度类型的一半,但精度(有效数字数量)小于double
long等同于long int
如果一个数是double,一个数是int类型,那么结果将变成double型
结果的类型具有重要意义
6.0/2=3.0近似值
6/2=3精确值
注意:赋值语句中,被赋值变量的类型并不改变由int和double类型组合而生成的类型,因为赋值发生在计算后
简单控制流程
if-else语句
复合语句
一个分支执行若干个语句,用花括号括起来
while语句
do-while语句
循环主体的一次重复叫做循环的一次迭代
递增递减操作符
无限循环
很多系统上用Ctrl+c来终止无限循环
程序风格
缩进
每个花括号都占一行
或者开头的花括号不单独占一行
注释
开头注释
程序包含在哪个文件中
谁写的这个程序
如何联系程序作者
该程序用途
最新修改日期
其他重要信息,如编号等
为常量命名
const修饰符
const修饰符声明的变量称为已声明变量
约定俗称已声明变量全部大写
小结
任何时候,只要希望用户从键盘中输入数据,就显示一个提示行,并始终回显用户的输入
第三章过程抽象和返回一个值的函数
自顶向下的设计
将任务分解为多个子任务,在分解为更小的子任务
预定义函数
实参
函数最开始使用的值
可有多个
返回值
函数计算得出的值
不超过一个
函数调用
函数调用是一个表达式,有函数名和带圆括号的实参构成
强制类型转换
static_cast<double>(9)
stastic_cast<double>()相当于一种预定义函数
古老的版本使用double(),应避免使用这种方式
程序员自定义函数
函数的描述
函数声明(函数原型)
指出了函数调用所需知道的一切
函数名称
参数个数
参数类型
我们在形参末尾通常加上_par
坚持注释来解释函数的返回值
另一种形式的函数声明
参数可以只有类型没有名称
只适用于函数声明,函数头必须列出形参名称
函数定义
描述函数如何计算它的返回值
函数头
比函数声明少一个分号
函数主体
声明
可执行语句
传值调用机制
形参通常被称为传值调用形参或者传值调用参数
指实参的值替换掉形参
函数定义的位置
在调用每个函数前,都必须出现函数的声明或者定义
所以如果将定义放在main部分前,就不需要包含任何函数声明
尽量不采取这种方式
过程抽象
把函数作为一个黑盒来编写和和使用叫做过程抽象
使用的程序员不需要查看函数主体来了解函数的工作原理
在注释中指出实参的所有要求,并指出实参在调用函数时,函数值的返回值
函数主体中使用的所有变量都应该在函数主体中声明(形参在声明中列出,无需重复)
使用伪代码来表示算法
用编程语言与自然语言来陈述你的算法
局部变量
如果在函数主体中声明一个变量,我们说该变量局部于此函数或者函数为它的作用域
如果在程序main中定义一个变量,我们就说该变量局部与程序的main部分,或者main部分作为他的作用域
与函数主体中的同名变量不相同
传值调用形参是局部变量
全局变量和全局常量
全局命名常量
将命名常量的声明放在程序的开始处位于所有函数主体和main部分之外
为了增强可读性,将所有include预编译指令,全局常量声明,函数声明分别集中放置(依照此顺序)
全局变量
不用const修饰符,可将普通变量声明为全局变量
尽量不使用这种有风险的方式
最好将命名空间局部化
重载函数名
为同一个函数名称提供两个或更多的函数定义
必须具有满足两个条件条件之一
不同数量的形参
部分不同类型的形参
例子:除法运算符/ double/int and int/int
如果只有返回值类型不同,则不能重载函数名称
第四章所有子任务的函数
void函数
void函数一般用于不返回值,或者返回多个值的函数
在void函数的结束花括号前有个隐式的 return;
可在if语句中使用return;来结束整个函数
main函数
一个返回int值的函数,需要一个return语句,部分编译器可省略return 0;
传引用调用形参
替换形参的第二种主要机制是传引用调用机制
传值调用形参替换的是实参的值,而传引用调用实参替换的是实参变量本身
函数调用中相应的实参必须是个变量
标记传引用调用参数应是用:&
&在类型名称末尾
函数主体对形参执行的任何操作会实际作用于于形参关联的内存位置
函数的默认参数
函数的形参如果需要默认实参,需要将有默认实参的形参放在函数列表的后面,这样在调用函数时,先给出实参将会取代还未被取代的形参
使用过程抽象
用函数来调用函数
因为我们将函数声明出现在main函数前,函数定义出现在main函数后,所以能在函数定义中调用其他函数,而不需要考虑先后问题
但不能将一个函数的定义放在另一个函数定义的主体
前条件和后条件
为函数注释时,分解为两种信息
前条件
指出函数调用所需的条件,不满足前条件,不应该使用这个函数
后条件
描述函数调用的结果,如果有返回值,需要描述这个返回值;如果修改了实参变量,描述对实参的值进行的修改
例子
void post_interest(double& balance , double rate)
前条件:balance是非符的存款账户余额
rate是表示成一个百分数的利率,比如5表示5%
后条件:是balance的值增加百分之rate
测试和调试函数
在一个程序中测试一个函数时,程序的其他函数都应该已经经过全面的测试和调试
驱动程序
尽可能简单的为测试函数获得参数值
stub(站位函数)
stub用于替换未经测试(或者尚未写好)的函数定义
不需要提供正确完整的计算过程,只需要返回测试函数所需调用未写出函数的正确返回值
小结
第五章I/O流——对象与类入门
流和基本文件I/O
流(stream)
由字符(或其他类型的数据)构成的流(flow)
流是对象
输入流
流向程序
输出流
流出程序
文件I/O
读取文件
采用从头到尾的读取文件方式,不能倒退读取,更改以前写入文件的任何输出
输入文件
程序从一个文件中获取输入或者输出到文件,必须借助流来连接文件
声明流
输入文件流的类型: ifstream
输出文件流的类型: ofstream
ifstream和ofstream类型包含在头文件为fstream的库里
需包含#include<fstream>
using namespace std;
流变量连接文件
称为打开文件,用open函数来完成
in_stream.open("infile.dat")
用instream流连接文件,用提取操作符>>从文件中获取输入
out_stream.opne("outfile.dat")
用ofstream流连接文件,用插入操作符<<将输出发送到文件
文件如果存在,open成员函数会丢弃原来的内容
文件如果不存在,会新建一个尚不存在的输入文件
程序在结束输入和输出时,每个文件都应该关闭
只有在程序正常终止的情况下,系统才会为你关闭文件
使用close函数来关闭文件
in_stream.close();
out_stream.close();
在流连接文件后,程序中将流名作为文件名来使用
类
如果一个类型的变量是对象,这个类型就称为类
决定了对象有哪些成员函数
如ifstream和ofstream类对象的成员函数open,close其实并不相同
成员函数调用中,圆点称为圆点操作符,圆点之前命名的对象叫做调用对象
利用成员函数fail来检测open的调用是否成功
格式
in_stream.open("stuff.dat");
if(in_stream.fail())
{
cout<<"Input file opening is failed!\n";
exit(1);
Windows系统用1表示错误,0表示成功
exit是一个预定义函数,需要包含#include<cstdlib> using namespace std;
}
文件I/O的include预编译指令
#include<fstream>
用于文件I/O
#include<iostream>
用于cout
#include<cstdlib>
用于exit
追加到文件
使用带有两个参数的open
outStream.open("important.txt",ios::app)
文件名作为输入
定义一个能容纳字符串变量,然后将open函数的实参换成这个变量(不需要""),这样用户就可以通过初始化这个字符串来决定输入的文件名
流I/O
用流函数格式化输出
precision成员函数
每个输出流都有这个成员函数,只对调用中指定的那个流生效
由编译器决定,是保留你给定位数的有效数字还是小数
setf成员函数
是set flag的缩写
flag是以二选一的方式来做一件事情的指令
流具体要做什么,将完全取决于标志
ios:fixed标志
导致流采用所谓的定点表示法(即平常的书写方法,而不是e计数法)
ios::showpoint标志
要求流总是在浮点数中包含一个小数点
ios::showpos标志
会为输入到那个流的正数加上正号(负号是自带的)
ios是input or output stream,::表示之后的术语是以::之前的术语为背景的意思
unsetf成员函数
能够取消setf函数设立的标志
width成员函数
告诉流一个输入项需要占多少个字符位置,多不截少会补
操纵元
一种以非传统方式调用的函数,流操纵元随即要调用一个成员函数
endl
setw
与width所做的事情一样,调用setw操纵元,就能将操纵元发送到输出流,输出流随即会调用width成员函数,在插入操作符<<后使用
#include<iosmanip> using namespace std;
setprecision
和成员函数precision所做的事情一样,用来规定小数字数,设置会一直生效,除非再次调用操纵元或者成员函数
同上
流能作为函数实参
函数的形参必须是传引用调用
检查文件尾
while(in_stream>>next)
当in_stream不能读取数字时,就不读取任何数字,并且自动转换为false结束循环
从技术角度看,是操作符>>针对流进行了重载
字符I/O
get和put成员函数
get成员函数
get成员函数允许程序读取输入的一个字符(不管这个字符是什么),将它存储到实参(char类型的一个变量)中
可以用此方法来检测一行的结尾,当实参传入为换行符时,回显输入
put成员函数
它能将参数的值输出到流,如cout.put('a');向屏幕输出a
将读取到的一个字符放到输出流中
putback成员函数
将读取到的字符放回到输入流
陷阱:输入中不期而遇的'\n'
注意用cin获取输入后的,会在输入字符后默认加上'\n',再想用cin.get()函数将值赋给目标变量时,赋值总会是'\n',应该采用new_line()丢弃输入行剩余的所有输入
eof成员函数
用来判断程序是否读取全部文件的内容
不取任何参数,直接通过输入文件流的成员函数方式调用,如果超越输入文件的末尾就为true
该函数只有在程序试图读取一个字符(文件尾标记)时,才能从false变为true,应该采用in_stream.get(next)来保证
预定义的字符函数
#include<cctype>
toupper()
返回大写形式
返回的是char字符对应的数字,应该使用char类型变量声明或者强制类型转换
tolower()
返回小写形式
isupper()
如果是大写,返回true
islower()
如果小写,返回true
isalpha()
如果是英文字母,返回true
isdigit()
如果是数字,返回true
isspace()
如果是空白字符,就返回ture
继承
派生类的另一种说法
派生类具有原类的性质和一些新的性质
如ifstream是istream的派生类,有istream不具有的open成员函数,同时能使用》
流是对象,所以istream是类
第六章定义类
结构
结构变量
结构标记
结构类型的名称
struct CDAccount
成员名称
{
double balance;
};
注意;
结构定义通常需要放在函数定义外,相当于全局声明,能在所有代码中使用
结构类型既可以作为函数返回值也可以作为函数参数
层次化结构
personal.birthday.year
对结构进行初始化
初始值多与struct成员就会出错,值的初始化顺序与成员变量在结构类型定义中顺序相同
结构就是一个定义好的类型
类
类是一个数据类型,它的变量就是对象
我们尽量遵守成员函数于成员变量出现的原则
封装
将多个项目(如变量,函数)合并到一个包(如对象)中的过程
作用域解析符::
无论是作用域解析符还是圆点操作符,都是指出成员函数的归属
操作符前面的类名通常称为类型限定符
类的编程规范
类应该保证有足够的成员函数来调用成员变量,不需要在主程序直接访问成员变量
建议将所有成员函数设置为私有成员
取值函数
获得一个类私有成员变量值的成员函数
赋值函数
更改一个类的私有成员变量值的成员函数
私有成员(函数,变量)
除非在一个成员函数的定义内,否则无法直接访问
程序默认开头为私有成员
能够使用赋值操作符让同类型对象赋值
用于初始化的构造函数
构造函数必须与类同名
构造函数定义不能返回一个值
构造函数放于public部分
构造函数的定义与其他成员函数定义一样
在声明对象时,会自动调用构造函数
构造函数的初始化区域
如BankAccount:BankAccount():balance(0),interest_(0.0)){cout<<"haha";}
括号内的是初始值,冒号之后,{之前是初始化区域,初始化部分或者全部成员变量
构造函数的实现细节是创造一个隐形的对象,来将隐形对象的值赋给声明对象
总是包括一个默认构造函数
指不提供参数的情况下调用的构造函数称为默认构造函数
无参数构造函数
在声明对象时,不应该在对象后添加括号来表示调用无参数构造函数,而在赋值语句中显式调用构造函数时,必须使用圆括号
BankAccount account2;
account1=BankAccount();
抽象数据类型
数据类型
值的一个集合以及为那些值定义的一系列基本运算构成
如果使用一个数据类型的程序员不能访问值和运算的实现细节,这个数据类型就叫ADT(抽象数据类型),如int数据类型(里面包括了+ - * 预定义库函数)
遵守规则
所有成员变量设置为类的私有成员
将所有基本操作设置为类的公有成员函数,并完善地指定如何使用每个公有成员函数
将任何辅助函数都设为私有成员函数
ADT接口
指出程序如何使用ADT
ADT实现
指出接口如何用C++代码实现
小结
第七章更多控制流程
程序语句的执行顺序称为控制流程
使用布尔表达式
优先级:! =类型 && ||
算数运算符优先级大于前面的逻辑运算符
短路求值
完全求值
尽量不要使用!操作符,如!time>limit 正确的是!(time>limit)
编译会将所有非零数字视为true,将0视为true
枚举类型
值由一系列int类型常量来定义的一种类型
enum Direction{ NORTH, SOUTH, FAST, WEST }
如果不初始化参数,参数的值从0开始,后一个参数时前一个参数的递增
多路分支
else虚悬问题
编译器总是将else与距离最近的上一个if配对,如果不使用 {} 的话
switch语句
总是包括一个default小节
如果没有break语句,在成功执行一个case语句后,仍然会继续执行下一个case
break语句只会终止循环语句的内循环,不会终止更高一级的循环
块
通常将包含变量声明的复合语句称为块
块内声明的变量称为块的局部变量
不包含变量声明的复合语句也可以称为块,块是用花括号封闭起来的C++代码
如果一个块不是函数主体,那么我们将它们称为语句块
这就是为何我们能在if-else 语句中声明局部变量
C++循环语句详解
循环
能多次重复一个或一系列语句的任何程序结构,每一次重复就叫做循环的一次迭代
再论递增递减操作符
++number
先返回number递增,再返回值
number++
先返回number值,再number递增
for语句
for语句循环头的任何声明,都假定它相对于循环主体是局部的
通常用四种方法来终止一个输入循环
已知长度的列表
每次迭代都询问
以哨兵值结束的列表
判断是否用完所有输入
为了简化嵌套循环,一个办法是将循环主体转变为一个函数调用
一定要确保循环使用的变量在循环开始之前正确的初始化
一定要确保循环不会多迭代或者少迭代一次
如果程序和算法很差,不要去修改,直接重新写
第八章友元函数和重载操作符
友元函数
不是这个类的成员函数,但是能够访问这个类的私有成员
将一个函数变为友元函数的唯一理由就是简化函数定义,并提高效率
取值函数和赋值函数是必要的,友元函数不能彻底替代他们的工作
如果函数只涉及一个对象就使用成员函数,多个使用友元函数
友元函数的函数声明能够放在public或private小节中,无论怎样它都是一个公共函数,最好是public中
digit_to_int函数
int digit_to_int(char c)
{ return ( int( c ) - int( '0' ) )
char类型的值是通过数字来实现的,因为数字是按顺序排列,int('0')+ 1=int('1')
const参数修饰符
如果使用一个传引用调用参数,而且函数不会更改参数值,那么就请加上const修饰符,这样的参数称为常量参数
从效率上来看,传引用调用参数要优于传值调用参数,这会在类参数中体现明显
因为调用对象的行为与传引用调用函数的行为非常相似,const也能用于调用对象
void output(ostream& outs) const;它能保证成员函数的调用不会改变对象的值
void money::output(ostream& outs) const {...
如果为特定类型的一个参数使用const,那么其他同样类型,不由函数调用更改的也应使用const
比如在一个参数为不可更改的类参数的函数中,调用这个类参数的成员函数,如果这个类的成员函数中没有包括const,编译器会认为有可能发生了更改而报错
如果const不是每次都适合一个类,那么永远不要为那个类使用它
针对任何类参数以及类的成员函数,只要允许,都应该使用const修饰符
重载操作符
friend Monney operator +(const Money& amount1,const Money& amount2);
重载操作符规则
最终重载的操作符至少有一个参数属于类类型
重载的操作符可以是但不一定是友元,操作符函数可以是类的一个成员,也可以是一个普通(非友元)函数
不能新建一个操作符,只能对现有的操作符进行更改
不能改变操作符的参数数量
不能改变一个操作符的有限级
以下操作符不能重载 圆点操作符(.) 作用域解析操作符(::) 操作符.*和?:
= [] ->操作符必须采用不同的方式进行重载
用于自动类型转换的构造函数
在进行如 full_amount=base_amount + 25;的操作室,如果没用重载操作符使类类型值与int类型值合并,那么应该包含一个构造函数获取单个int值参数,这样能自动将25转化为类类型的值,比如Money(double amount);
重载一元操作符
++ 和 --
重载>>和<<
它们是二元操作符,如cout<<"1"<<"hello"; 在调用后返回cout本身再进行下一次的调用,这个操作符需要使用传引用调用,因为你需要传回一个流,而不是流的值
如 friend istream& operator >>(istream& ins,Money& amount);
如friend ostream& operator <<(ostream& outs,Money& amount);
第九章独立编译和命名空间
独立编译
将一个程序分解为不同部分,保存在不同文件,独立编译,在程序运行时(之前)连接到一起
ADT回顾
接口文件
实现文件
public部分是ADT接口的一部分,private部分是ADT实现的一部分,但是不能将其分解为两个文件,所以将整个类的定义都放在接口部分(私有成员依然保持隐藏)
程序员自定义头文件
include"XX.h"
.h是头文件的扩展名
预定义头文件
include<XX>
实现文件
XX.cpp
实现文件名最好与接口文件名同名,拓展名为程序文件名的拓展名
应用程序文件
包含程序的文件
使用#ifndef
C++不允许重复定义一个类,我们需要标记一个代码小节
在头文件中使用
#ifndef DTIME_H
如果标志没有被定义
#define DTIME_H
定义一个与文件名换为大写字母的,下划线取代句点的标志
类
#endif
如果include预编译指令重复处理,会忽略直到此语句的一切内容
命名空间
是名称定义(如类定义和变量声明)的一个集合
命名空间的定义
namespace XX{}
可以为单个命名空间使用任意数量的命名空间分组,如来保持函数声明和定义的格式
命名空间的使用
using预编译指令
作用范围在它所在的那个块
using声明
在只使用少数函数时,指定不同命名空间的同名函数
using ns1::fun1
ns1是命名空间
fun1是函数
无名命名空间
用来解决辅助函数的“局部”问题
using预编译指令后无名称
一个定义相对于一个编译单元来说是“局部”的
每一个编译单元都有一个无名命名空间
无名命名空间中定义的每个标识符相对于编译单元都是“局部”的
全局命名空间
在默认情况下,有一个隐式的using预编译指令指出你要使用的全局命名空间
第十章数组
数组入门
数组中独立的变量
索引变量(下标变量,元素)
索引变量的数目
数组的声明长度
基类型
一个数组的所有索引变量都是同类型的
数组索引总是从0开始,结束于比数组长度小1的一个整数
初始化数组
int b[]={5,12,11}
可以同时声明和初始化,并且数组长度可以自动生成
函数中的数组
数组形参
既不是传值调用,也不是传引用调用参数
因为它将数组的地址告诉函数之外,还告诉数组的基类型和数组长度
数组实参
是用于替换a[]这样的数组形参的实际参数值
规范
在函数声明和定义时,使用a[],和数组声明长度(编译器会忽略a[]里的数字)
在函数调用时,使用a,数组声明长度
const参数修饰符
常量数组形参
void show_the_world(const int a[],int size of a)
同样面临不一致使用const参数问题
数组编程
数组搜索算法
数组排序算法
选择排序法
数组和类
类数组
声明类数组时,会调用默认构造函数来初始化索引变量
hahh[i].ssd
数组作为类成员
haha.ssd[i]
多维数组
让一个数组有多个索引
char page[30][100]
由数组构成的数组
第一个参数才是真正的索引,其他参数时基类型描述的一部分
在函数头或者函数声明中使用一个多维数组参数时,第一维的长度不要给出,剩余其他维的长度必须用方括号给出
void get_page (char p[][100],int size_dimension_1)
子主题
第十一章字符串与向量
字符串的一种数据类型
C字符串
以'\0'来终止的一个字符数组
C字符串变量
本质上就是一个字符数组,知识在末尾包含'\0',它代表一个字符
在声明时可初始化,可自动生成长度
为C字符串赋值
陷阱:为C字符串使用=和==
本质上是数组,不能使用上述操作符
在声明时可以使用=进行初始化,不叫做赋值
使用strcpy函数(#include<cstring>)
strcpy(a_string,"hello")
此版本不会检测是否超过了声明长度
使用strncpy函数(#include<cstring>)
strncpy(another_string,a_string_variable,9)
第三个参数为指定最多复制的字符
检测C字符串的相等
使用strcmp函数(#include<cstring>)
几个函数都不需要包括uisng namespace std;它们都位于全局命名空间
strcmp(c_string1,c_string2)
如果字符串不同
返回true
在依次比较字符时,如果两个字符的数值编码不同,测试停止
如果c_string1的字符小于c_string2的字符,那么会返回负数,反之正数
字符串相同返回0
检测字符串的长度
strlen("hello")
返回字符串长度
拼接字符串
strcat(string_var,"in spain")
C字符串输入和输出
<<插入操作符
不能读入整行输入
getline()函数
getline(a,80)
后一个参数指定能容纳的最大字符数,注意'\0'字符
C字符串到数字的转换和可靠输入
预定义函数atoi()(#include<cstdlib>)
atof()
alphabetic to floating point
atol
alphabetic to long
标准string类
名称<string>库里定义,定义放在std命名空间
string能够进行=,+,<<,==等操作符操作
string类的默认构造函数
string phrase
将对象初始化为空字符串
将phrase初始化为空字符
string noun("ants")
将对象初始化为一个与C字符串参数相同的一个字符串,但是不以'\0'结束
string noun="ants";
两者相同
string类的I/O
cin>>读取的字符串以第二个空白结束
使用getline()函数读取整行语句
这个版本的getline函数包含在<string>库中,不是成员函数
getline(cin,line)
geline的其他版本
getline(cin,line,'?')
此版本将指定停止信号为'?',而不是原来的'\n'
使用getline函数时,可把它视为一个void 函数,但它实际上会返回第一个参数的引用
陷阱:混合使用"cin>>变量;"和getline
cin>>n;
getline(cin,line)
getline会读取cin>>n后留下的'\n'
length()成员函数
last_name.length()
因为string类能像数组一样,用last_name[i]访问编号为i的字符
拥有自动扩容能力
我们通常使用at函数来检测非法索引值
last_name.at(i)
如果编号i的索引越界,会有错误提示
last_name.at(i)=‘X’;
find()成员函数
str.find(str1,pos)
能从pos位置查找,返回str1在str中首次出现的索引
string对象与C字符串之间的转换
strcpy(a_c_string,string_variable)
strcpy不允许string作为第二个参数
a_c_string=string_variable.c_str();
c字符串不能使用=赋值
strcpy(a_c_string,string_variable.c_str())
c.str()成员函数能够将string类型的转化为相应的C字符串
向量
想象成能在程序运行时改变长度的数组
声明向量
vector<Base_Type> v;
vector<Base_Type>表示一个模板类(类名)
会调用一个默认构造函数
该构造函数会创建一个空的向量对象(不含元素)
声明并初始化有参数指定的位置数目,元素会被初始化为0
vector<int> v(10)
v[i]=12
只能为向量某元素赋值,但是不能用于初始化
不能超过向量长度,必须使用push_back添加更多的元素才行
包含在<vector>库中,定义在std命名空间
要想在向量中添加元素应该使用push_back()成员函数
这种添加是依次添加的
v.push_back(1);
为0号元素添加值为1
size()函数
size函数返回一个向量的长度,值的类型时unsigned int(非负的整数值)
应该用强制类型转化来将其转换为int类型
效率问题
长度
向量中元素的个数
size()
容量
当前实际分配了内存的元素的个数
capacity()
一旦容量不够,系统会自动倍增容量,我们可以手动增加容量
reserve()
v.reserve(v.size()+10)
将容量设置为向量当前元素的数目+10
此函数在参数值小于当前容量的前提下,不一定会执行
resize()
主动改变向量的长度
v.resize(24)
如果原长度大于24,24之后的元素会丢失
第十二章指针和动态数组
指针
指针是一种结构(变量的内存地址),它允许我们对计算机内存进行更大的控制
计算机内存划分为编号内存地址(称为字节),用一系列相邻的内存位置来实现变量
指针变量的声明
用于容纳指针的变量必声明为具有指针类型
double *p1
它能容纳一个指向double类型变量的指针
p1表示指针
提领操作符*
*p1表示指针指向的变量
取址操作符&
&v1表示v1变量的地址,p1=&v1表示p1指向变量v1
操作符new
创建一个新的动态变量,它具有指定的类型,返回指向这个新变量的指针
Mytype *p;p=new MyType;
如果类型是一个拥有构造函数的类,会为动态变量调用默认构造函数,也可以指定初始化列表来调用其他构造函数
mtPtr=new MyType(32.0,17)
自由存储"堆"
系统为动态变量保留的一个特殊的内存区域
如果没有足够的内存,new操作符回默认种植程序
delete操作符
销毁一个指针指向的动态变量
这样有可能会产生虚悬指针问题
自动变量
普通变量称为自动变量,系统会在程序终止后自动销毁这些变量,而静态变量不同于普通变量
定义指针类型
typedef int* IntPtr
IntPtr p1 就能将p1直接定义为int类型指针
动态数组
动态数组是程序运行时才确定长度的一种数组
创建动态数组
typedef double* DoublePtr;
DoublePtr d;
d=new double[10];
如果方括号内没有数字,那么系统会分配一个足够大的内存给动态数组
指针其实指向数组第一个索引变量,所以与数组的类型相同
销毁动态数组
delete [] a;
不能省略方括号,如果省略方括号,会只告诉系统销毁一个某类型的变量
不能将调用new创建的指针变量来赋给其他任何指针值,否则在销毁时会发生混乱
指针运算
*(d+i)
将指向d[0]的指针递增i个那一变量占用的字节数,也就是指向d[i]
可以使用递增递减操作符
两个指针之间的减法
返回的是两个地址之间的索引变量数目
多维动态数组
typedef int* IntArrayPtr;
IntArrayPtr *m=new IntArrayPtr[3];
由数组构成的数组,所以应该先创建一个以为的动态数组,由int*类型的指针构成
for(int i=0;i<3;i++)
m[i]=new int[4];
创建int类型的数组
创建了3X4的int数组
delete [] m[i];
销毁int类型的数组
delete [] m;
销毁int*类型的数组
销毁动态多维数组
类和动态数组
string类
析构函数
类的一个成员函数,它在类的对象超出作用域之后自动调用
局部指针变量并不会在函数调用结束后自动delete,如果没有析构函数,在类中使用者又不能意识到使用了指针变量,那么会引起内存不足的问题
陷阱:指针作为传值调用参数
如果传值调用参数是指针类型,很有可能指针变量的指针值没有变,而指针的变量值改变
复制构造函数
只有一个参数的构造函数,这个函数具有与类相同的类型,而且必须是一个传引用调用参数,通常还要加上const参数修饰符
复制构造函数的主要作用是为指针创建一个新的动态数组,而不是将指针指向同一个数组引起混乱
凡是使用了指针和操作符new的类都应该使用复制构造函数来避免错误发生
重载赋值操作符
要考虑string类的重载赋值操作符
小结
第十三章递归
面向任务的递归函数
面向值的递归函数
递归思想
第十四章模板
用于算法抽象的模板
模板前缀
template<class T>
它告诉编译器后面的定义或者函数声明是一个模板而T是一个类型参数(T可替换成任意名称)
许多编译器不支持模板的函数声明,我们通常不使用函数声明,确保定义位于使用它的同一个文件中,而且确保定义位于使用它的位置之前
许多编译器不允许对函数模板进行编独立编译,所以确保上述约定生效,也可以使用一个单独文件来存储而使用include来包容那个文件
先写出普通函数,再修改换成函数模板
用于数据抽象的模板
类模板的语法
子主题
第十五章指针和链表
节点和链表
节点
节点的声明
struct ListNode
{string item;
int count
ListNode *link
我们在struct中定义指针并且将指针指向包含指针的struct
};
typedef ListNode* ListNodePtr;
head(表头)
head头指针的声明
ListNodePtr head;
箭头操作符
合并了提领操作符*和原点操作符的功能
可以指定动态struct或对象的一个成员,一个给定的指针则指向那个成员
一个链表应用程序
第十六章继承
继承基础
继承细节
多态性
第十七章异常处理
异常处理基础
用于异常处理编程技术
第十八章标准模块库
迭代器
容器
泛型算法