C++ Primer (暂时完结)

C++ Primer

C++ 预备知识

面向对象的编程(OOP)

image-20210802174233194

什么是类,什么是对象

类包含 数据和操作

image-20210802174655217

泛型编程

独立于特定的数据类型,

和数据类型无关,不管你是什么数据类型,只实现这个功能

image-20210802175703932

image-20210802180020700

image-20210802180227120

第二章 开始学习C++

main 函数框架

image-20210802181521123

g++是编译c++工具的

image-20210802182645810

任何一个程序的开始都是从main开始

image-20210802182751129

单片机可以不用main,动态链接库也可以不用main

注释

//两个斜线,单行注释
/**/ 多行注释

2.1.3 C++预处理器 和iostream 文件

#include <iostream>
using namespace std:
想要输入输出,就要有这两个

我包含了iostream文件,iostream里面所有的文件都会被包含在里面~

image-20210802184626446

input output 流

image-20210802184729038

image-20210802184751350

image-20210802184827973

image-20210802184838787

想调用c库的话,前面加c 把点h去掉

名称空间

using 编译指令

image-20210802185020652

如果我们想要有两个封装好的函数

两个,都有wanda() 函数

我们到底用哪个?

image-20210802185233573

我们使用这个就可以找到具体的一个

image-20210802185430883

如果不加using namespace的话,那就需要std:: 这样

然后加了的话,就会默认来自于std这个名称空间

image-20210802185653850

这样的话,我们只会使用一点点,

声明之后,只开放了std的方法 count endl cin,这仨而且之后都可以随便使用

第二章 输出输入

image-20210802205325465

image-20210802205454191

image-20210802205501767

输出流,将字符串流到输出

image-20210802205525546

右侧信息插入到输出流中

image-20210802205641117

image-20210802205655669

运算符重载,

这两个运算符相同

image-20210802205739295

多个符号,编译器会进行识别

endl控制符

end line

结束这一行

作用是为了重启一行

image-20210802205838913

image-20210802205854158

换行符

image-20210802210024780

cout << "" << endl

规范的书写格式

c++源码风格

image-20210802210127478

程序清单2.2

#include<iostream>
int main() {
	using namespace std;
	cout << "hello world\n";
	cout << endl;
	return 0;
}

C++ 首次使用前进行定义即可

image-20210802210502166

#include<iostream>
int main() {
	using namespace std;

	int carrots;

	carrots = 25;
	cout << carrots << endl;

	int c = 10;
	cout << c << endl;

	return 0;
}

image-20210802210541788

打印的是字符串25 在内存中是存的11001 数字

cout 会字符串输出

#include<iostream>
int main() {
	using namespace std;

	int carrots;

	carrots = 25;
	cout << carrots << endl;

	int c = 10;
	cout << c << endl;

	cout << "i have" << c << "is" << carrots << endl;
	return 0;
}

输入

cin 输入流

image-20210803104332973

image-20210803104809396

#include<iostream>

int main() {
	using namespace std;
	int carrots;

	cout << "hello can you guess" << endl;

	cin >> carrots;

	cout << "noooooo " << carrots << endl;

	return 0;
}

image-20210803104959298

一行比较长 可以这么写

类的简介

就相当于是一个数据类型了

image-20210803105342673

数据和方法对吧,和java一样的

image-20210803105522934

image-20210803105530387

使用对象内的方法,也可以使用运算符重载

image-20210803105832998

也就是<<

将信息传递给输出流对象

2.4 函数

有返回值的函数

例如那个sqrt() 函数

x = sqrt(6.25)

这个是已经写好的函数,

求平方根

image-20210803110610223

image-20210803110744836

传参的类型,返回的类型,

必须要知道这两个

缺少类型就报错了

image-20210803110939661

说明他返回就是double

函数声明,带分号

image-20210803111030744

提供原型,有两种方法

image-20210803111136206

第二种方法更好,

函数原型在main前面

image-20210803111319410

#include<iostream>
# include<cmath>

int main() {
	using namespace std;
	int carrots;

	cout << "hello can you guess" << endl;

	cin >> carrots;
	
	cout << "noooooo " << carrots << endl;

	double area;
	cout << "Enter the floor area, in square feet,of your home:";
	cin >> area;
	cout << sqrt(area);
	return 0;
}

image-20210803112042924

函数变体

image-20210803112252577

函数带多个参数

pow() 求几次方

rand () 不带参数的函数

bucks () 函数可以i没有返回值

image-20210803112334660

没返回值不带参数

标准库中的函数~

自定义函数

image-20210803112810584

image-20210803113241359

#include<iostream>
# include<cmath>

void simon(int n);

int main() {
	using namespace std;

	simon(3);
	return 0;
}

void simon(int n) {
	using namespace std;

	cout << "Simon says touch your toes " << n << " times." << endl;

}

带返回值的参数

image-20210803114215897

#include<iostream>
# include<cmath>

void simon(int n);
int stonetolb(int sts);
int main() {
	using namespace std;

	cout << "Enter the weight in stone:";
	int stone;
	int pounds;
	cin >> stone;
	pounds = stonetolb(stone);
	cout << pounds << endl;
	return 0;
}

void simon(int n) {
	using namespace std;

	cout << "Simon says touch your toes " << n << " times." << endl;

}
//1 stone = 14 lbs
int stonetolb(int sts) {
	int pounds = 14 * sts;
	
	return pounds;
}

编程练习

image-20210803115910867

#include<iostream>
# include<cmath>
using namespace std;

int hiahia(long x);
int main() {
	cout << "Wum1ng " << "Peking" << endl;
	long x;
	int c;
	cin >> x;
	c = hiahia(x);
	cout << c;

	return 0;
}

int hiahia(long x) {
	return x * 220;
}

image-20210803120036367

image-20210803120055934

image-20210803120224564

image-20210803120318554

第三章 处理数据

C++原生带着,内置的数据类型

基本数据类型,|复合数据类型

整形 浮点型 | 字符串,数组,结构体

简单变量

image-20210803124644605

int braincount;
braincount = 5;

image-20210803124823931

braincount 标记名称

变量名

字母数字下划线

不能数字开头

没有关键字

两个下划线,一个下划线,编译器保留使用,

image-20210803124906589

区分大小写的

他存放的只是一个整数的子集

基本整形

  • char

  • short

  • int

  • long

  • long long

    image-20210803125623753

image-20210803130104546

直接声明就可以

sizeof运算符

求在内存空间中的占用

image-20210803133300263

定义常量 我们 一般全用大写~

头文件limits

包含一些宏定义

image-20210803133416501

image-20210803134059575

image-20210803134339365

image-20210803135047641

初始化

声明和赋值合并在一起

image-20210803135343436

也可以用圆括号进行赋值

image-20210803135516688

也可以使用{} 花括号初始化器

可以应用于任何的数据类型

image-20210803135909882

无符号类型

image-20210803140139487

最大值会扩大

image-20210803140707377

image-20210803140731260

让他们均+1 然后会发生越界

image-20210803140959569

整型字面值

image-20210803154120095

十进制,十六进制,八进制

image-20210803154222168

cout 默认是输出的十进制输出

image-20210803154404078

image-20210803154915906

切换cout

image-20210803155013379

然后是各个进制的

C++ 如何确定常量的类型

可以添加后缀

image-20210803155955717

L ul ull

char类型,字符和小整数

char其实就是整形,他会存储成整型,只不过会对应一个表而已

一个字节就够了 2^8

ASCII

image-20210803161355213

输入一个字符

image-20210803161624243

cin 和cout

image-20210803162720596

可以看出来,是77 同时 是M

image-20210803162743339

如果我们+1 就会变成 78 也就是N

类里有变量,函数,我们需要访问对象对吧,

cin,cout 可以访问类内的函数

image-20210803163132622

我们调用 cout 的put函数试试

转义字符

image-20210803163752326

image-20210803163803763

转义序列使用十六进制

bool类型

image-20210803164951270

bool 类型转换成了int 也就是01转换

const 限定符

定义为了常量

不允许被修改

字母都大写的话,一般就是去使用#define

image-20210803165804425

image-20210803165849929

一般使用
const int xx = 111;

这样好

只希望某个常量在某个中实现,我们用const

image-20210803170147462

使用const 不用define

3.3浮点数

image-20210803170435812

E表示法

image-20210803170508942

image-20210803170518145

setf()

迫使输出定点表示,防止转换为E表示法

image-20210803171425855

迫使显示后六位

cout默认打印后六位

image-20210803171638163

image-20210803171651532

cout会删除结尾的0

#include<iostream>
# include<cmath>
#include<climits>
using namespace std;

int main() {

	cout.setf(ios_base::fixed, ios_base::floatfield);
	float tub = 10.0 / 3.0;

	const float million = 1.0E6;
	cout << "tub = " << tub << endl;
	return 0;
}






这里是带乘法的

#include<iostream>
# include<cmath>
#include<climits>
using namespace std;

int main() {

	cout.setf(ios_base::fixed, ios_base::floatfield);
	float tub = 10.0 / 3.0;

	const float million = 1.0E6;
	cout << "tub = " << tub << endl;

	cout << "A million tubs " << million * tub << endl;
	return 0;
}

image-20210803172400478

这里已经出现问题拉

后面都是0了

因为float精度达不到

image-20210803172600413

image-20210803172604535

我们使用double 保证了精度

#include<iostream>
# include<cmath>
#include<climits>
using namespace std;

int main() {

	cout.setf(ios_base::fixed, ios_base::floatfield);
	float tub = 10.0 / 3.0;

	const float million = 1.0E6;
	cout << "tub = " << tub << endl;

	cout << "A million tubs " << million * tub << endl;


	double mint = 10.0 / 3.0;
	cout << mint * million;
	return 0;
}

浮点数的优缺点

运算的时候,浮点数运算会降低

image-20210803173227786

a和b差1.0 但是 相减为0,精度降低了

image-20210803173248798

float double 精度

浮点数如何存储呢?

单精度 32bit

double 双精度 64 bit

image-20210804105456645

都要遵循 IEEE 标准,任意一个浮点数都是以科学计数法来表示

二进制的科学计数法

例如 8.25

整数+小数
1000. 01
0.25 * 2  =0.5 取处整数0
0.5 * 2  = 1 取出整数 1

1000.01转换为科学计数法,
1.00001*2^3
整数部分一定是1

计算机存储科学计数法,有符号的
符号正负(1 bit)
正数 0 负数 1
2^3    2^-3

image-20210804110811723

因为要表示正负次幂,所以

2^(127+3)
计算机中存储浮点数,
一共32位,小数部分23位
精度是6位-7位,说的是十进制,2^23次约等于 10^6.923
符号(1位)+指数位(8位)+小数部分(0001000000000000000)
double类型,小数部分52个

C++ 算术运算符

求加减乘除

image-20210804113639420

#include<iostream>
# include<cmath>
#include<climits>
using namespace std;

int main() {
	float hats, head;
	cout.setf(ios_base::fixed, ios_base::floatfield);
	cout << "Enter a number:";
	cin >> hats;
	cout << "enter another number : ";
	cin >> head;
	cout << "heat= " << head <<"\n"<< "hats" << hats << endl;
;
	return 0;
}

image-20210804113819491

很明显,加出来不对

image-20210804113932136

位数会一直往下增加

浮点数他要变二进制,小数一直×2

image-20210804114534690

这行注释掉,就对了

四舍五入之后,才会对,之前是强制显示后六位

image-20210804115119192

加减乘除都会有这个问题

float类型,真不行

我们要使用double类型

image-20210804115338483

整数除法

image-20210804115437796

向上转数据类型

位数加长,默认转为了double类型的除法

image-20210804115542438

强制转float的话,加一个F

image-20210804115607935

image-20210804115714773

image-20210804115742052

复合类型

4.1 数组

数组存相同的数据类型

image-20210804140529647

数组中的内容在内存中是连续排列的

image-20210804140653887

这三个点必须要有

short months[12]

声明通用通用格式
typeName arrayName[arraysize]


里面必须存放的是常量

image-20210804140849038

数组中的编号从0开始~

程序员要确认好数组下标不越界

image-20210804141757702

#include<iostream>
# include<cmath>
#include<climits>
using namespace std;

int main() {
	int yams[3] = {7,8,6};
	int yamscosts[3] = { 20,30,5 };
	cout << "The total yams = " << yams[0] + yams[1] + yams[2] << endl;
	cout << "The package with" << yams[1] << "yams cost " << yamscosts[1] << endl;
	return 0;
}

数组初始化规则

image-20210804142206329

定义的时候才能给值

一小部分初始化,其他都为0

也可以为空,编译器会自动计算个数

short things[] = {1,5,3,8}

变量类型缩窄

其实说白了就是一个变量赋值给另一个变量的时候发生溢出的情况,万一发生了缩窄转换,程序一般是不会报错的,这将非常不利于bug调试,因此要尽可能避免它。话不多说,看看例子吧。

#include <iostream>
using namespace std;

int main()
{
	int a = 5000000; //-2147483648~2147483647
	short int b = a;
	cout << b << endl;
	return 0;
}

image-20210804142721368

可以很明显地看到结果不是我们想要的,甚至不符合溢出。那么怎么避免变量类型缩窄转换呢?C++11提供了初始化列表就可以避免这一问题。

image-20210804142729342

#include <iostream>
using namespace std;

int main()
{
	int a = 5000000, b = 10000; //-2147483648~2147483647
	short int c{a};
	short int d{b};
	cout << c << endl;
	cout << d << endl;
	return 0;
}

image-20210804142839535

默认都为0

image-20210804142922995

有效位降低是不允许的!

也就是缩窄

double放在long中不允许

image-20210804143136313

数组替代品 vector

字符串

image-20210804143211925

一种是,C语言风格,把字符串存在数组里

第二种,基于string类库的方法

字符串要以\0结尾

第一个就不是string

第一个是字符数组

image-20210804143546071

他会自动加上\0 编译器加进来的

image-20210804143741109

image-20210804143753339

单引号是字符,双引号是字符串

双引号里面是两个,外加一个\0

字符串常量存的是地址

在数组中操作字符串

strlen 字符串长度

sizeof() 占用内存空间

image-20210804145844303

15字节

strlen字符串长度忽略\0

image-20210804150224979

第二次输入就没了

我们加了个空格

image-20210804150247234

cin使用空白字符(空格,回车,制表符)

确定字符串

他认为当前结束了

dreeb会存到缓冲区

image-20210804150709737

image-20210804152343652

都会放在输入缓冲区

直接去缓冲区读取,

getline()

每一次读取一行字符串输入

cin.getline()

image-20210804152725481

设置20 最多会读取19个字符

#include<iostream>
# include<cmath>
#include<climits>
# include<cstring>
using namespace std;

int main() {
	const int Size = 20;
	char name[Size];
	char dessert[Size];
	cout << "11" << endl;
	cin.getline(name, Size);
	cout << "22" << endl;

	cin.getline(dessert, Size);
	cout << "delicious" << dessert << endl;

	return 0;
}

image-20210804155937168

get()

和getline一样,都是对行的接收

image-20210804155919157

get会丢弃换行符,遇到换行符结束

image-20210804160028244

输入后直接会跳两次

image-20210804160052813

空字符,没输入

image-20210804160438747

image-20210804160555443

中间接受一个回车

image-20210804160747326

函数重载

参数列表不同参数名字相同

image-20210804161039509

image-20210804161435794

string 类简介

可以通过数组的类型来操作string,下标之类的都可以

image-20210804162542887

image-20210804162646276

赋值,拼接,附加

可以把string对象,赋值给另一个string对象

image-20210804162740650

image-20210804162905227

附加

#include<iostream>
# include<string>
using namespace std;

int main() {
   char charr1[20];
   char charr2[20] = "jaguar";
   string str1;
   string str2 = "panther";
   cout << "Enter a kind of feline"<< endl;
   cin >> charr1;
   cout << "Enter another kind of feline : ";
   cin >> str1;
   cout << "Here are some felines:\n";
   cout << charr1 << " " << charr2 << " "<< str1 << " " << str2 << endl;

   return 0;
}

image-20210804163221497

strcp(charr1,charr2)

复制

sstr1+=""

strcat(charr,“juice”);

z字符串连接

string类I/O

image-20210804163449038

如何用getline读取一大串,存在string中

image-20210804163713045

strlen 查看一下,发现和20不一样,

因为我们没有进行输入值,内存中随机的

我们查看str.size()

image-20210804164141979

image-20210804164251270

cin.getline

getline

image-20210804164423798

image-20210804165232308

结构体设定

image-20210804165303470

允许声明结构体省略struct

image-20210804165413800

填充的时候需要逗号

image-20210804165433175

image-20210804165529216

外部声明,在所有中都可见

perk在main函数内可见

image-20210804165602083

同一种结构体类型就能直接赋值

结构体和类型直接声明

image-20210804194741576

同时赋值也可以

image-20210804194751752

不推荐这么干

image-20210804195302894

image-20210804195327083

结构体的位字段

image-20210804195410613

标志着你有多少位,多少bit

位字段是低级编程

image-20210804195538501

4.5 共用体

union是一个数据格式

image-20210804200949954

image-20210804200715035

联合体中,三选一,同一时间,只能使用一个

image-20210804200805061

image-20210804200929014

和结构体很相似

image-20210804201021440

共用体长度为最大长度

image-20210804201536849

#include<iostream>
using namespace std;

union one2all {
	char ch;
	int n;

};

int main() {
	one2all num;
	cout << "sizeof(num)= " << sizeof(num) << endl;
	return 0;
}

image-20210804201731934

比如你存一个 A 他int 输出 65 他字符串输出A

同一个内存空间

结构体放结构体,结构体放联合体都可以

image-20210804202012659

可以用联合体查看计算机是大端模式还是小端模式

4.6 枚举

C++ 的 enum 工具提供了创建符号常量的方法

也相当于struct这种

image-20210804202110393

image-20210804202214111

这样的话,red,orange,等等,都变成了常量

里面的每个值都是整型,从零开始

image-20210804202501680

枚举类型声明这种变量,

spectrum band

同时,只能将定义枚举的枚举量赋值给枚举的变量

只能给0-7或者是red等

枚举类型,只能赋值,没有算数运算

image-20210804202815571

image-20210804202840530

可以转换为int 比如转成0 1 之类的

低转高

image-20210804202915068

枚举类型,为了定义常量,而不是创建新的常量

设置枚举量的值

image-20210804203107413

比如认识整数哟

image-20210804203257276

他有上限和下限,这里赋值就可以

他的限制必须是最大的2的幂次 (2的三次 =8 二的四次-1 也就是15)

image-20210804203357383

4.7 指针和自由存储空间

image-20210805101527656

存储到何处?

值为多少,

存储的信息是什么类型

求出他值得地址,

image-20210805103558314

加一个取地址符号

如何声明指针

指针里面放地址

image-20210805104854316

#include<iostream>
using namespace std;



int main() {
	int updates = 6;
	int *p_updates;
	p_updates = &updates;
	cout << "value : updates = " << updates << endl;
	cout << "p_updates = " << p_updates << endl;
	return 0;
}

image-20210805105057918

4.7.2 指针的危险

image-20210805105152710

他地址并不明确,给地址里面送值会有bug

image-20210805105651092

4.7.4 使用new来分配内存

指针是访问内存的别名

new运算符分配内存,比malloc好多了

new会返回内存块的地址

image-20210805110515276

int *pn = new int;

typeName * pointer_name = new typeName

image-20210805111330726

#include<iostream>
using namespace std;



int main() {
	int nights = 1001;
	int *pt = new int;
	*pt = 1001;

	cout << "nights value = " << nights << "address " << &nights << endl;
	cout << "int value = " << *pt << "address value = " << pt << endl;
	double * pd = new double;
	*pd = 10000001.0;
	cout << "double value = " << *pd << "address " << pd << endl;
	return 0;
}

image-20210805111344221

使用delete释放内存

只会删除内存空间,释放掉,不会删除ps指针,

new 和 delete要成对使用,

delete后不要delete,结果不可预知

delete 不呢个释放声明变量所获得的内存

image-20210805111627816

image-20210805111712083

没new,就不能delete

小数据,直接定义就行,大量数据,还是new方便

image-20210805114250749

静态创建数组,浪费,new的时候,不需要就可以不用开创空间

动态联编

使用new创建动态数组

image-20210805114404140

int * psome = new int [10];

释放数组:

delete [] psome;

如果不带方括号

释放的只是第一个元素

image-20210805114639010

image-20210805114756661

指针是变量,数组值是 常量

数组不能增加/运算之类,

指针,数组,指针算术

image-20210805143708644

image-20210805144350913

数组的动态联编和静态联编

image-20210805144509867

使用new[]

image-20210805144520202

不用不分配

指针和字符串

image-20210805144716313

相当于打印了rose第一个字母r,一次性取出所有字符串,rose 直到找到\0

strncpy() 拷贝多少个

image-20210805145257571

防止溢出

image-20210805145354644

new char 数组

动态开辟空间

new动态创建结构体

优于编译时候

image-20210805145527150

结构体类型指针

image-20210805160905284

image-20210805160931927

image-20210805160957458

这样也可以实现

接收动态字符串开辟空间函数

image-20210805161446124

image-20210805161700926

image-20210805161740836

类型组合

数组的替代品

image-20210805161910066

模板类vector

image-20210805162241199

用的是圆括号了这儿

vector<typeName> vt(n_elem);

vector代价,效率比较低

功能强大

模板类array

array长度是固定数组

array<int ,5> ai;

image-20210805162736275

image-20210805163704130v

vector 是存储在堆中,肯定和其他存储的不一样】

#include<iostream>
#include<vector>
#include<array>
using namespace std;



int main() {
	int nights = 1001;
	double a1[4] = { 1.2,2.4,3.6,4.8 };
	vector<double> a2(4);
	a2[0] = 1.0 / 3.0;
	a2[1] = 1.0 / 5.0;
	a2[2] = 1.0 / 7.0;
	a2[3] = 1.0 / 9.0;
	array<double, 4> a3 = { 3.14,2.72,1.62,1.41 };
	array<double, 4> a4;


	return 0;
}

使用成员函数,可以使用at来进行检测下标越界

image-20210805164328280

循环

image-20210805165241875

这样没加括号,他会等号分开两边

都不认识

image-20210805165826623

输出 0 1 之类的

image-20210805170900188

阶乘的输出

第八章 函数探幽

C++ 内联函数

为了提高程序运行速度

image-20210805180150808

运行速度快

image-20210805180800578

常规函数,很废时间

花费精力,入栈出栈

代码执行短的话,方便内联

image-20210805201143377

image-20210805201239051

square就是内联函数

#include<iostream>

using namespace std;

inline double square(double x) { return x * x; };

int main() {
	double a, b;
	double c = 13.0;

	a = square(5.0);
	b = square(4.5 + 7.5);
	cout << "a = " << a << "b = " << endl;
	cout << "c = " << c << endl;
	cout << "Now c = " << square(c++) << endl;
	
	return 0;
}

8.2 引用变量

引用就是定义变量的别名

image-20210805201817437

创建引用变量

image-20210805201853474

rats 和rodents 可以互换

引用和指针还是有区别的

image-20210805202630895

将引用用作函数参数

形参实参一回事儿了

形参操纵实参,

脱离C语言

image-20210805203814240

名字一样,参数不同,也可以哟~

8.5函数模板

交换两个数的值

怎么写呢?

image-20210806101646997

函数重载,也可以使用函数模板

c++函数模板功能可以自动完成这一过程

image-20210806101833597

template <typename anytype>

和class差不多

image-20210806101922692

类型名称任意选

为了方便,一般都写T ,图省事

可以接收任意类型~

image-20210806102705808

两次替换,可以模板函数,也可以函数重载

image-20210806103308652

#include<iostream>

using namespace std;

template<typename T>
void Swap(T &a, T &b);

int main() {
	int i = 10;
	int j = 20;
	cout << "i,j = " << i << "," << j << "." << endl;
	Swap(i, j);
	cout << "after swap ,now i,j = " << i << "," << j << endl;

	double x = 24.5;
	double y = 81.7;
	cout << "i,j = " << x << "," << y << "." << endl;
	Swap(x, y);
	cout << "after swap ,now i,j = " << x << "," << y<< endl;
	return 0;
}

template <typename T>
void Swap(T &a,T &b) {
	T temp;
	temp = a;
	a = b;
	b = temp;
}

编写是一个,但是编译器会最终编译生成两个

8.5.1重载的模板

如果说我们想交换数组,必须要重载,不重载很明显就不可以

image-20210806105114652

输出没有任何问题

#include<iostream>

using namespace std;

template<typename T>
void Swap(T &a, T &b);
const int LIM = 8;
void show(int arr[], int n);

int main() {
	int i = 10;
	int j = 20;
	cout << "i,j = " << i << "," << j << "." << endl;
	Swap(i, j);
	cout << "after swap ,now i,j = " << i << "," << j << endl;

	int d1[LIM] = { 0,7,0,4,1,7,7,6 };
	int d2[LIM] = { 0,7,2,0,1,9,6,9 };
	cout << "origianl arrays" << endl;
	show(d1, LIM);
	show(d2, LIM);

	return 0;
}

template <typename T>
void Swap(T &a,T &b) {
	T temp;
	temp = a;
	a = b;
	b = temp;
}
void show(int arr[], int n) {
	for (int i = 0; i < n; i++) {
		cout << arr[i] << " ";

	}
	cout << endl;

}

我们来写模板

image-20210806105945291

#include<iostream>

using namespace std;

template<typename T>
void Swap(T &a, T &b);
template<typename T>
void Swap(T a[], T b[], int n);
const int LIM = 8;
void show(int arr[], int n);

int main() {

	int d1[LIM] = { 0,7,0,4,1,7,7,6 };
	int d2[LIM] = { 0,7,2,0,1,9,6,9 };
	cout << "origianl arrays" << endl;
	show(d1, LIM);
	show(d2, LIM);
	Swap(d1, d2, LIM);
	cout << "Swapped arrays = " << endl;
	show(d1,LIM);
	show(d2, LIM);

	return 0;
}

template <typename T>
void Swap(T &a,T &b) {
	T temp;
	temp = a;
	a = b;
	b = temp;
}
template<typename T>
void Swap(T a[], T b[], int n) {
	T temp;
	for (int i = 0; i < n; i++) {
		temp = a[i];
		a[i] = b[i];
		b[i] = temp;
	}
}
void show(int arr[], int n) {
	for (int i = 0; i < n; i++) {
		cout << arr[i] << " ";
	}
	cout << endl;

}

8.5.2 模板的局限性

image-20210806110203065

image-20210806110739729

交换结构体,直接把所有东西都交换了

image-20210806110802109

我只想交换钱,

image-20210806110826089

重载,参数类型,数量需要不同

8.5.3 显式具体化

template <> void Swap(job &j1,job &j2)

image-20210806111705501

告诉编译器。如果传过来的是job类型,就不能去用其他的模板

image-20210806113336500

成功替换

#include<iostream>

using namespace std;

template<typename T>
void Swap(T &a, T &b);
template<typename T>
void Swap(T a[], T b[], int n);
const int LIM = 8;
void show(int arr[], int n);


struct job
{
	char name[40];
	double salary;
	int floor;
};

template <> void Swap<job>(job &j1, job &j2);
void show(job &j);

int main() {

	int d1[LIM] = { 0,7,0,4,1,7,7,6 };
	int d2[LIM] = { 0,7,2,0,1,9,6,9 };
	cout << "origianl arrays" << endl;
	show(d1, LIM);
	show(d2, LIM);
	Swap(d1, d2, LIM);
	cout << "Swapped arrays = " << endl;
	show(d1,LIM);
	show(d2, LIM);

	job Rick = { "Rick",100,10 };
	job Jack = { "Jack",1100,11 };
	show(Rick);
	show(Jack);
	Swap(Rick, Jack);
	show(Rick);
	show(Jack);

	return 0;
}

template <typename T>
void Swap(T &a,T &b) {
	T temp;
	temp = a;
	a = b;
	b = temp;
}
template<typename T>
void Swap(T a[], T b[], int n) {
	T temp;
	for (int i = 0; i < n; i++) {
		temp = a[i];
		a[i] = b[i];
		b[i] = temp;
	}
}
void show(int arr[], int n) {
	for (int i = 0; i < n; i++) {
		cout << arr[i] << " ";
	}
	cout << endl;

}
void show(job &j) {
	cout << j.name << ":" << j.salary << "onfloor" << j.floor << endl;
}
template <> void Swap<job>(job &j1, job &j2) {
	double t1;
	int t2;

	t1 = j1.salary;
	j1.salary = j2.salary;
	j2.salary = t1;

	t2 = j1.floor;
	j1.floor = j2.floor;
	j2.floor = t2;
}

优先显示具体化的函数

8.5.4 实例化和具体化

image-20210806120010031

自己选择 合适的函数调用

image-20210806120210655

我们定义一个模板函数和一个非模板函数

image-20210806174943976

非模板函数优先

image-20210806175052811

#include<iostream>

using namespace std;
template<class T>
T lesser(T a, T b) {
	return a < b ? a : b;
}

int lesser(int a, int b) {
	a = a < 0 ? -a : a;
	b = b < 0 ? -b : b;
	return a < b ? a : b;
}
int main(void) {
	int m = 20;
	int n = -30;

	double x = 15.5;
	double y = 25.9;
	cout << lesser(m, n) << endl;
	return 0;
}

image-20210806175305318

这样,优先使用模板函数

image-20210806175338853

#include<iostream>

using namespace std;
template<class T>
T lesser(T a, T b) {
	return a < b ? a : b;
}

int lesser(int a, int b) {
	a = a < 0 ? -a : a;
	b = b < 0 ? -b : b;
	return a < b ? a : b;
}
int main(void) {
	int m = 20;
	int n = -30;

	double x = 15.5;
	double y = 25.9;
	cout << lesser(m, n) << endl;

	cout << lesser<>(m, n) << endl;
	return 0;
}

image-20210806175557349

告诉模板函数,参数强转为int

image-20210806175619043

单独编译

工程可能会包含很多源代码和头文件

除了内联函数,其他定义不放头文件

image-20210806183835926

可以写.c .cpp 专门来调用其他

上面那些东西都放头文件里面

一个 功能一个cpp比较香

image-20210806190720342

把两个拆开,然后编译,然后链接

image-20210806191257251

保证了项目只会定义一次,

if not define 如果没有定义过,然后才会去定义头文件,

有if 必须要有endif

image-20210806194025143

双引号,代表去你当前目录去获取头文件

函数调用

file1.cpp

# include<iostream>
#include "coordin.h"
using namespace std;
int main(void) {
	rect rplace;
	polar pplace;

	cout << "Enter the x and y values :";
	while (cin >> rplace.x >> rplace.y) {
		pplace = rect_to_polar(rplace);
		show_polar(pplace);
		cout << "Next two number (q to quit):";

	}
	return 0;
}

函数原型声明 .h

#pragma once
#pragma once
#ifndef __COORDIN_H__
#define __COORDIN_H__

struct polar
{
	double distance;
	double angle;
};

struct rect {
	double x;
	double y;
};

polar rect_to_polar(rect xypos);
void show_polar(polar dapos);


#endif // !__COORDIN_H__

函数定义

file2.cpp

#include<iostream>
#include<cmath>
#include "coordin.h"

using namespace std;

polar rect_to_polar(rect xypos) {
	polar answer;

	answer.distance = sqrt(xypos.x * xypos.x + xypos.y * xypos.y);
	answer.angle = atan2(xypos.y, xypos.x);

	return answer;
}
void show_polar(polar dapos) {
	const double Rad_to_deg = 57.29577951;

	cout << "distance = " << dapos.distance << endl;
	cout << "angle = " << dapos.angle * Rad_to_deg << " degree " << endl;

}

存储秩序性,作用域和链接性

image-20210809181220011

形参,实参,以及参数的区域,c学过了

使用C++ 11 中的auto

register auto

image-20210809193143340

extern

image-20210809193211834

声明函数,说明这个参数是外来的,这里只是想用到

作用域解析运算符

image-20210809193615620

::

加上以后相当于调用全局变量

image-20210809193637034

这里的::warming ,表示使用的全局版本

support.cpp

#include "support.h"

using namespace std;

void update(double dt) {
	warming += dt;
	cout << "Update" << warming << endl;


}
void local(void) {

}

external.cpp

# include<iostream>
# include "support.h"

using namespace std;

double warming = 0.3;

int main(void) {
	cout << "Global warming is " << warming << "degrees." << endl;
	update(0.1);
	cout << "Global warming is " << warming << "degrees." << endl;
	return 0;
}

support.h

#pragma once
#ifndef __SUPPORT_H__
#define __SUPPORT_H__

#include<iostream>
extern double warming;
void update(double dt);
void local(void);

#endif


静态持续性,内部链接性

image-20210809193947223

image-20210809194030930

内部只能内部文件用,

image-20210809194145005

就近原则,差不多~

file1.cpp

image-20210809194659434

file2.cpp

image-20210809194706990

无链接性的局部变量

其他函数,文件,看不到你

image-20210809195225124

cin.get() 获取内容

image-20210809195755426

image-20210809195742972

image-20210809195909636total只再第一次调用。count会掉一次初始化位0

image-20210809200102444

total 值之后就不变了

说明符和限定符

auto 自动匹配 变量类型

register 分配内存分配到寄存器

image-20210809200333388

image-20210809200500361

CV限定符

volatile和mutable

固件用的比较多

const

链接性为内部的,不会影响到其他文件

函数和链接性

C++ 不允许一个函数中,定义另一个函数,所有的函数存储持续性为静态

extern 函数指出另一个文件中定义,是可选的,默认不写

函数static 定义,只能在一个文件中使用

image-20210809200731989

语言的链接性

C语言一个名称一个函数

image-20210809200808322

C++ 中同一个名称可能多个函数

image-20210809200835572

编译器可能会改他的名字

存储方案和动态分配

new开辟,delete释放

使用new进行初始化

image-20210809200955109

image-20210809201025877

开辟内存空间,初值为6

image-20210809201050598

image-20210809201122997

image-20210809201142137

定位new运算符

image-20210809201306464

可以指定,存放的位置

使用new

处理特定位置i访问的硬件或者是创建对象

image-20210809201310440

image-20210809201353737

image-20210809201424626

指定在那个内存空间中,

指定在buffer1里面

new定位运算符,需要new头文件

image-20210809201834475

image-20210809201851729

image-20210809202156524

c++,我们想要输出字符串的地址,buffer,这样肯定式字符串,我们要强制转换,让他知道我们出地址

image-20210809202230568

image-20210809202343187

很明现,这两个地址不一样

image-20210809202513056

image-20210809202914339

我们发现,pd2和buffer一样的

delete的时候

image-20210809203018870

delete 不能用于定位的new运算符

delete 删除的是动态内存,动态释放内存,new也是

image-20210809203513883

9.3 名称空间

不同厂家类库,可能会冲突~

image-20210809203628499

9.3.2 新的名称空间特性

image-20210809203736400

我们可以使用任意一个名称,用的时候,写具体就可以

名称空间包含名称空间也可以,默认外部,但是不能在代码块中

image-20210809203830192

新的名称,随便加

image-20210809203844444

image-20210809203908771

当然,需要作用域解析运算符

指名道姓

using 声明和using 编译指令

image-20210809204011161

image-20210809204030477

image-20210809204112150

放到了局部声明区域

编译指令

image-20210809204151941

image-20210809204219246

image-20210809204253850

image-20210809204815632

如果使用fetch,优先局部变量,不会进行冲突

image-20210809205314291

名称空间的套用

image-20210809205328035

这样using的编译指令

image-20210809205338587

未命名的名称空间

image-20210809205446494

从声明开始,到结束

第十章 类和对象

通过public方法,调用private的隐私数据

头文件只做类的声明,不会把他具体写出来

访问控制

image-20210810105140190

只有通过public能改private

控制对成员的访问,公有还是私有

没private,数据默认私有,

image-20210810105838144

stock00.h 头文件

#pragma once
#ifndef __STOCK00__H__
#define __ STOCK00__H__
#include<string>

class Stock
{
private:
	std::string company;
	long shares;
	double share_val;
	double total_val;
	void set_total() { total_val = shares * share_val };
public:
	void acquire(const std::string &co,long n,double pr);//哪一个公司的股票
	void buy(long num, double price);
	void sell(long num, double price);
	void update(double price);
	void show();

};


#endif

10.2.3 实现类成员函数

image-20210810110123221

用 :: 标识类

image-20210810110201735

image-20210810110210139

我们可以跟另一个也可以定义同样的函数

类内,不需要指定

内联方法

image-20210810111949374

定义位于类声明中的函数都将自动成为内联函数

image-20210810112229622

函数声明时候,就定义了,这个就自动成为了内联函数

如果有inline 也会是内联函数

image-20210810112509807

放在外面实现

类的定义

stock00.cpp

#include<iostream>
#include "stock00.h"



void Stock::acquire(const std::string &co,long n,double pr) {
	company = co;
	if (n < 0) {
		std::cout << "Number of share can't be negative;" << company << std::endl;

	}
	else
		shares = n;

	set_total();
}

void Stock::buy(long num, double price) {
	if (num < 0) {
		std::cout << "number of shares can't be negative,Transaction is aborted" << std::endl;

	}
	else {
		shares += num;
		share_val = price;
		set_total();
	}
}
void Stock::sell(long num, double price) {
	using std::cout;
	if (num) {
		std::cout << "number of shares can't be negative " << std::endl;

	}
	else if (num > shares) {
		cout << "you can't sell more than you have " << std::endl;

	}
	else {
		shares -= num;
		share_val = price;
		set_total();
	}
}

void Stock::update(double price) {
	share_val = price;
	set_total();
}

void Stock::show() {
	std::cout << "Company: " << company << std::endl;
	std::cout << "Shares: " << shares << std::endl;
	std::cout << "share price : " << share_val << std::endl;
	std::cout << "TOtal worth:" << total_val << std::endl;
}

10.2.4 使用类

#include<iostream>
#include"stock00.h"


int main(void) {
	Stock fluffy_the_cat;
	fluffy_the_cat.acquire("wuwu",20,12.5);//第一次获取一个股票
	fluffy_the_cat.show();
	
	fluffy_the_cat.buy(15, 18.125);//再买多少zhi,meizhi多少钱
	fluffy_the_cat.show();
	
	fluffy_the_cat.sell(400, 20.00);//尝试卖400份,查看报错
	fluffy_the_cat.show();
	
	return 0;
}

image-20210810113410568

image-20210810114101864

image-20210810114645337

卖多了,提示,不能卖

类的构造和析构函数

image-20210810115201768

image-20210810115617708

不能将参数当作构造函数的参数

避免混乱,我们在数据前面加前缀m_

构造函数没有返回值~~

stock10.cpp

#include<iostream>
#include"stock00.h"

Stock::Stock(const std::string &co, long n, double pr) {
	company = co;
	if (n < 0) {
		std::cout << "Number of share can't be negative;" << company << std::endl;
		shares = 0;
	}
	else
		shares = n;
	share_val = pr;
	set_total();
}

C++ 提供了两种方法来构造函数,第一种是显式的 调用构造函数

使用构造函数

image-20210810150942461

image-20210810152250202

如果使用默认参数,这里在声明中直接填入值(默认值)

image-20210810152436583

另一种方式是函数重载,来定义另一个构造函数,一个没有参数的构造参数,

上面两种只能采用其一。否则会冲突

image-20210810152945557

usestock2.cpp

#include<iostream>
#include "stock00.h"
int main(void) {
	/*
	Stock stock1("Nanosmart", 12, 20.0);
	stock1.show();

	Stock stock2 = Stock("Boffo objects", 2, 2.0);
	stock2.show();
	*/
	Stock stock1;
	stock1.show();
}

stock.cpp

#include<iostream>
#include"stock00.h"
/*
Stock::Stock(const std::string &co, long n, double pr) {
	company = co;
	if (n < 0) {
		std::cout << "Number of share can't be negative;" << company << std::endl;
		shares = 0;
	}
	else
		shares = n;
	share_val = pr;
	set_total();
}*/

Stock::Stock() {
	company = "no name";
	shares = 0;
	share_val = 0.0;
	total_val = 0.0;
}

stock00.h

#pragma once
#ifndef __STOCK00__H__
#define __ STOCK00__H__
#include<string>

class Stock
{
private:
	std::string company;
	long shares;
	double share_val;
	double total_val;
	void set_total() { total_val = shares * share_val; };
public:
	Stock();
	//Stock(const std::string &co, long n, double pr);
	void acquire(const std::string &co,long n,double pr);//哪一个公司的股票
	void buy(long num, double price);
	void sell(long num, double price);
	void update(double price);
	void show();

};


#endif

stock00.cpp

#include<iostream>
#include "stock00.h"



void Stock::acquire(const std::string &co,long n,double pr) {
	company = co;
	if (n < 0) {
		std::cout << "Number of share can't be negative;" << company << std::endl;
		shares = 0;
	}
	else
		shares = n;
	share_val = pr;
	set_total();
}

void Stock::buy(long num, double price) {
	if (num < 0) {
		std::cout << "number of shares can't be negative,Transaction is aborted" << std::endl;

	}
	else {
		shares += num;
		share_val = price;
		set_total();
	}
}
void Stock::sell(long num, double price) {
	using std::cout;
	if (num) {
		std::cout << "number of shares can't be negative " << std::endl;

	}
	else if (num > shares) {
		cout << "you can't sell more than you have " << std::endl;

	}
	else {
		shares -= num;
		share_val = price;
		set_total();
	}
}

void Stock::update(double price) {
	share_val = price;
	set_total();
}

void Stock::show() {
	std::cout << "Company: " << company << std::endl;
	std::cout << "Shares: " << shares << std::endl;
	std::cout << "share price : " << share_val << std::endl;
	std::cout << "TOtal worth:" << total_val << std::endl;
}

image-20210810153048225

传参了,就一定不是默认的构造函数

image-20210810153152309

第三个,默认的构造函数

10.3.4 析构函数

image-20210810154313230

对象使用完毕后,会自动调用析构函数,

如果在构造函数中new来分配内存,析构函数将调用delete释放

析构函数也没有返回值和类型

image-20210810154445579

析构函数没有参数

~Stock();

同时,因为上一个没new,所以,析构函数为空

image-20210810154536807

image-20210810154624248

10.4 this指针

image-20210810160024522

如果我们需要比较,两个类的时候,

我们要比较两个类对象,

指向用来调用成员函数的对象,this表示正在访问的对象,

image-20210810163247598

tips

image-20210810163258908

*this 这样表示了整个调用对象

image-20210810163423399

这里的return就是*this

this指针指向调用成员的对象

10.5 对象数组

image-20210810171056578

构造函数初始化数组