引言:

C++一门重要的语言。

C++ 是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言,支持过程化编程、面向对象编程和泛型编程。

C++ 被认为是一种中级语言,它综合了高级语言和低级语言的特点。

a1fd79b76d984470869677b556f22854.png

第一阶段:C++基础入门

第一章:数据类型、运算符与表达式

1、C++基本结构

4f47f5918a8648deb0d77f066984b025.png

2、单工程多main函数

74b8dd5e73fd4d7fa609fd5f07ed3eb0.png

3、手动编译C++代码

利用MinGW-w64软件;

e0562ed9596f4610941dbd3b3e96e56b.png

4、cout打印输出

cout <<...<<...<<...<<endl(换行)

c2e8cdab903440819a6656107e3b0d45.png

cout 语句中,字符串需要用双引号括起来;字符用单引号括起来;其他数据类型(如整数、浮点数等)可以直接使用,不需要加引号。

49247458214549e6a64e95d9fd8fbe10.png

5、字面常量

3bbf716c932a4d30bf6eb8a5a889d1d3.png

6、标识符与关键词

变量的命名即标识符,不能作为标识符的即关键词;

9cfe5767040242c4b78cef668cae4d1a.png

7、符号常量

cc2817e102df43b9af8b5e038a0ee665.png

8、变量的基础使用

4ba1ad6c9373407a937f166348132296.png

5185a4a6e5cc4be18c12aff96a4908fc.png

9、变量的特征

0179269e2edc478ea7acd24d4ea36da0.png

10、变量的快速定义

75fc1357b6e244039a1774b0fd3fc4c9.png

11、标识符的限制规则:

40e2080333a9456194f8aaf574d0bd25.png

12、数据类型(整型)

13da22ffc93b4420ae9592c10cda80b2.png

c1bd337729e947ec90fbfa0d2ac81de5.png

13、有符号和无符号的数字

fcb9f8fe5d9b4d48b483dbe1d31bd093.png

其中unsigned必须写,并且代表无符号,只有的;signed可写可不写,有符号,有正有负;

同时可简写,即unsigned int可简写为u_int;

14、数据类型(实型)

290bd6a0b71b480eabe6033f4e077029.png

浮点数:小数

04dc62efc8ed46fb9a5b571cbfe8890d.png即整数位、小数点、小数位;

0da3bd4c72a347c78cb5169eb49e057e.png

15、C++常量类型的确定

3b85e837325c41aeba30d0b66e4e9238.png

90c4a876965d462cb3465e3df75e384e.png

893c5e97cf4d4ac7acc542a3442c9d80.png

16、数据类型-char类型

da407b79165b47b2a26e019a44778e20.png

char类型可存储内容:ASCII表;

202d4e42efd14597bbf871c0d75916b1.png

8d50b12ca0224be2bbbea0a788e7caa3.png

17、转义字符

967624cc65224fd2a666a6a4c690b838.png

50ce3d9bd4c64623b9f3ba9a5b27b475.png

单独打印“与‘,需要\消除其字符意义,\“与\‘才能打印出来“与‘。

5ccd306f97ab47a3b6107ca9a8948278.png

18、数据类型-字符串

ba930d32643a43afaed25f0d8706146e.png

字符数组在赋值语句下不能进行赋值;

19、字符串的拼接

a56ac6102a9e40728eee9b54a7f7ba46.png

其中利用to_string()函数将非字符串转换为字符串之后,可用+号进行拼接。

20、数据类型-布尔型

b2b71a2748844695854a1995af242820.png

21、cin数据输入

eb59a757eb0d43c1b23d784a4739a53e.png

22、cin中文乱码

f419b9ffdc684bc7b66175ca330f765b.png

23、算术运算符

6f9b5ee162454fa5ae960e036d8dd484.png

b5ffb699d66846b0a32e3239032e3210.png

560f483593ed475d99613e2cdc429194.png即整除结果(10/3=3);

24、赋值运算符

773b11344f4c46b8a159518fd0c4da8d.png

ce1d4a6694614498ae8f283c0330c97b.pngbbb358ef564a492ca44070fc3b22b1b0.png

25、比较运算符

b1c31ae3d5b8481797b494f073d6ce89.png

583f1903492749e1b079280527e87b83.png

  • C语言风格:

2102836be2164951bd21f43657c5b68c.pngf7d62ee822ff47f3984a0bf1b76e270c.png第一个0是false不相等,第二个0是相等。

  • C++风格:

d11821231d7745c9a4534a66968111ac.png9b95620b95154fa3b77d8abc0e44dcba.png记得s5==s6要加小括号();

26、逻辑运算符

7f6f210fd5a24c468d8c6655a868575e.png

27、三元运算符

c7c77f0b3d0546e1a90e5533495c23f9.png

91bb60c87e9749458b9abaef70a35dbe.png

第二章:控制结构

28、if与if else与else if逻辑判断语句

1c976eaeea224fd28ac5cb1963f4ef51.png

d32ee13c1d434eeab33c6097a22b38dd.png

deeb9c76bb114ec0a00227b1ab90d745.png

else if语句里面的几个条件互斥,只能成立一个。

79450e7a1eaa49d4b66e40432c2129ba.png

29、逻辑判断语句的嵌套

6981ffc1fef349308c42f86a3e818aaf.png

30、Switch控制语句

bfcb1b6a375b4355ae2afeed9e66e79c.png

3bb5fbaa63304d0682944a276d435cae.png

31、枚举类型

a837b02ca6b849c9a31b97c23d609093.png

9216b30dc09e4e1d9a66a95163f39144.png

例子:e2bc5c8a1dec4979bf802e777aa00c29.png

97f6a480838a449790dbc907568e5df2.png

32、while循环语句

b441855082ff45a3acad763352b2ecb3.png

即条件表达式为true(1)的时候,执行code,然后再返回来看条件表达式,还是1就继续执行code......

ff6bdc74184f4c37a5f97d084e59a6fe.png

33、do while循环语句

e5fa0021acae450b811c73477dfb043e.png

778fec31f0ce41cda29595f40515f610.png

34、while循环嵌套

65974c2421e74107837f701416abde47.png

35、for循环语句

5a360d632e8e41cb90798eecdaee0527.png

9231acde56e94e0db2bd62b34f723896.png

两者执行步骤均从1到4;

78294b9deba94564960ef9f1d4d91c34.png

36、变量的作用域

e0d66e03871247f197e24dcf70e5bb86.png

37、循环中断语句(continue与break)

d1fac02ce3fa463aba5300818862ac67.png

例子程序:

2dc76bc7926845a79f9cb808e498e6dd.png其中两个都是对所在for循环起作用;

输出结果分别是:1-20的奇数,1-20数字(到20终止);

9fea877b83a84a8db81390bf16c1cb90.png

38、goto语句

655549bf55b448a4adf6befbc378de98.png

51c7ac2c4e17465396978f025afd7f34.png

第三章:数组、指针、引用与结构体

39、数组的定义

大盒子装进同类型小物品;

57a2c47534b44d92a987ed89cf0b1774.png

0b475304d06846538be5e6855d4b325e.png

c6648f76aaa645dc99dda7bf2559dd7e.png

v[6]表明数组内可存放6个元素,分别是v[0]到v[5];而不是到v[6];

注:

  • 数组声明+赋值快捷写法

80554daadc524acfaf958e01288dd853.png

  • cout输出的时候,数组不加引号,数组的输出不加引号是因为数组本身并不是一个字符串,而是一个由多个元素组成的集合,你需要处理每个元素进行输出。引号“the six”只是为了用于表示字符串字面量,而数组本身是一个数据结构,不是字符串。

657fbf01fb10464a8ae4e3c8aa8744c4.png

970229304d49442bacb62e0dd5459caf.png

40、数组的特点

特点1:

ac6829f18de84d2a987b0e55981daf8e.png

特点2:

ca0d6f8f747449bb97db16e14aa39e43.png

两种类型都代表数组v大小固定为5;

特点3:

29c1c0e0b5e34db6ae999f24a599a22d.png

其中sizeof函数可以计算变量的空间占用大小;

特点4:

b9725bbc0c674b29b014eb406adf769d.png1改为11,;2改为22;

特点5:

341954c62958413eab4ffe3303a84a7f.png

v本身不存数据,通过记录的内存地址去访问0号元素,再加(int)4个字节,访问1号元素等等;

c18322401af84bd9901aab076e4588c9.png64692ad1095a4562b36ff8c5f83cc9df.png直接输出的v9代表的是一个内存地址,即0号元素(v[0]);

41、数组的遍历

b1cd2e4c9c3b4e6cb36b5cec5c7d2a5c.png

ac38bf06d4234270a32e08dc237b6303.png

42、字符数组

378d43e668dc49d0b0f3d6b531659f9c.png

7a2a745dd76d4d52bc2c2373caf81da4.png

hello用sizeof函数的出来是6个元素;(多了一个/0)

上述代码输出为h,e,l,l,o,/0;

78a6c2ef59fa4949bb90554fedfbf1bd.png

采用string类型:string 类型用于表示和操作文本数据,是编程中非常常用的一种数据类型。

43、多维数组

a9557dc97202402a820adc1718ef8eaf.png

二维数组:

d27b09d51a95485c8b51debddc564722.png

上下两种表达,要不先声明,一个一个赋值;要不直接声明+赋值。

三维数组:

cb4b687ef5354e67938d0e124cbf724b.png

上下两种表达,要不先声明,一个一个赋值;要不直接声明+赋值。

44、多维数组的遍历

3c10999485c74fffbf0d1afbdd9eb60e.png

45、指针基础

指针是一个变量其值另一个变量的地址。通过指针,可以间接访问和操作存储在该地址上的数据。

定义变量的时候加一个*,那么后面的变量存的就是一个内存地址,而不是数字等;通过&来取得某个变量的地址,并存放到p中;

若是取数组arr[ ]的地址,不用加该符号&,因为数组本身记录的就是地址,并且指向的是数组中的0号[0]元素地址;如下图:

易错分辨:
int a = 10;
int* ptr (int *ptr)= &a;  // ptr 是一个指向 a 的指针;*的位置不会影响语义。
int value = *ptr = a;  // 解引用 ptr,获取 ptr 指向的地址的值,即 a 的值,赋值给 value

如上图所示,直接对指针变量进行了赋值,可以直接修改内存;

46、野指针和空指针

下一个人不吃上一个的残羹剩饭;

指针变量本身所占字节数:

64位系统:8字节;32位系统:4字节

对野指针直接进行赋值,所赋的值可能会存储在一个未知的区域,造成安全隐患,如下所示:

为避免上述问题,引入空指针的定义:

总结:

47、指针运算

例如:int类型4个字节,所以加一个int的地址即4个字节;

48、动态内存分配

例如

如下伪代码:

上述伪代码称为:(自动)静态内存分配

对此,采用的方法为:

其中delete不能删除C++的静态内存;

49、数组元素的移除

50、数组元素的插入

51、指针悬挂

52、常量指针(const)

常量指针(const pointer)是一种特殊类型的指针,用于确保指针所指向的值不能被修改。

分为三类例如:

第一种:

第二种:

第三种:

第四章:函数

51、结构体基本应用

struct 是结构体(structure)的缩写。它是一种用户定义的数据类型,用于将不同类型的数据组合在一起。结构体允许你创建一个包含多个数据字段的复合数据类型,常用于组织和管理数据。

52、结构体成员默认值

53、结构体数组

结构体数组例如:

54、结构体指针

指针访问结构体内成员的时候采用-<;

55、结构体指针数组

结构体指针数组是指一个数组,其中的每个元素都是指向结构体的指针。

上图中用的是.来访问内容,因为p1是指针,但是p1中的[0]号元素是结构体,所以用.

56、函数的概念

57、函数的基础语法

在main前编写函数,然后在main内使用;

返回值类型有整型int、浮点型double、字符型char、string等;

  • 函数与int main(){}同级,所以函数不可定义在main内部。
  • 其中a,b形式参数(形参);3,5实际参数(实参);

58、无返回值函数和void类型

void:空

没return返回值,所以不用(=)接收它的结果;

“即不需要你的结果,直接去干”;

59、空参函数

60、函数的嵌套调用

61、参数的值传递与地址传递

其中把x,y的值给了a,b;所以函数里的交换和x,y本身无关;

故上图是单纯的值传递;

下图换个写法,是地址传递,x,y的值完成了互换;

总结:

62、函数传入数组

63、引用的基本概念

三个特点:

类似:引用为空,会报错;

必须一开始就初始化,引用了谁(b引用了a);

引用的代码实现:

64、引用传参

  • 单单x,y值传递是无法对主函数main中的x,y进行改变(无法改变实参),如下图:

  • 引用传递会直接改变main中的值(会改变实参),如下图:

  • 指针地址传参,可根据地址改变实参

以上三种的区别与联系:

常量引用:在函数形参列表中,可以加const修饰形参,防止形参改变实参;

65、函数返回指针及局部变量的生命周期

即在子函数内部创建的变量无法作为函数的返回值,因为会在子函数执行之后原地销毁;

应当如下编写代码:

关于 return sum 中不加 * 的原因:

return sum; 这行代码中,我们返回的是指针 sum,而不是指针指向的值。

  • sum 是一个指针,它保存的是动态分配内存的地址。如果在 return sum; 中加上 *,即 return *sum;,那么你将返回指针 sum 所指向的值(在本例中是 a + b 的和)。但函数声明中要求返回一个 int* 类型(即指针),所以我们不需要加 *,因为我们要返回的是 sum 指向的内存地址,而不是内存中的值。

简而言之,sum 本身就是一个指针,*sum 是解引用操作,表示返回指针指向的内容。return sum; 返回的是指针,而不是它指向的值。

总结:

  • sum 是指针,*sum 是指针指向的值

  • 函数 add 的返回值类型是 int*,所以直接返回 sum,而不需要加 *

66、static关键字

当变量所占的空间较小的时候可以使用例如int就4个字节;但是要是有很多个元素的数组,会占用大量空间,此时应当直接使用new和delete进行动态手动管理内存如上点65;

67、函数返回数组

例如点61和点64。

第二阶段:C++核心编程(剩余部分在文件核心编程中)

第一章:程序的内存模型

1、内存四区

C++程序在执行时,将内存大方向划分为4个区域

  • 代码区:存放函数体的二进制代码,由操作系统进行管理的
  • 全局区:存放全局变量和静态变量以及常量
  • 栈区:由编译器自动分配释放, 存放函数的参数值,局部变量等
  • 堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收

内存四区意义:不同区域存放的数据,赋予不同的生命周期, 给我们更大的灵活编程

(1)程序运行前

​ 在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域

代码区:

​ 存放 CPU 执行的机器指令

​ 代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可

​ 代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令

全局区:

​ 全局变量和静态变量存放在此.

​ 全局区还包含了常量区, 字符串常量和其他常量也存放在此.

该区域的数据在程序结束后由操作系统释放

总结:

  • C++中在程序运行前分为全局区和代码区
  • 代码区特点是共享和只读
  • 全局区中存放全局变量、静态变量、常量
  • 常量区中存放 const修饰的全局常量  和 字符串常量

(2)程序运行后

栈区:

​ 由编译器自动分配释放, 存放函数的参数值,局部变量等

​ 注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放

堆区:

​ 由程序员分配释放,若程序员不释放,程序结束时由操作系统回收

​ 在C++中主要利用new在堆区开辟内存

总结:

堆区数据由程序员管理开辟和释放

堆区数据利用new关键字进行开辟内存

第二章:函数高级

1、函数的默认参数

在C++中,函数的形参列表中的形参是可以有默认值的。

语法: 返回值类型  函数名 (参数= 默认值){}

例如:

int func(int a, int b = 10, int c = 10) {
return a + b + c;
}

//1. 如果某个位置参数有默认值,那么从这个位置往后,从左向右,必须都要有默认值
//int func2(int a = 10, int b){  //错误代码
//}


//2. 如果函数声明有默认值,函数实现的时候就不能有默认值;声明和实现只能有一个有默认值;
int func2(int a = 10, int b = 10);  //加分号即函数的声明
int func2(int a, int b) {           //即函数实现
	return a + b;
}


int main(){

cout << func(10) <<endl; //3. 指仅传入a的值即可,因为b,c在子函数中已经设置为默认参数了,不过如果这个地方传入了b,c的值,程序输出则优先用已传入的值,而不是子函数中的默认值;

system("pause");

return 0;

} 

2、函数的占位参数

C++中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置。

语法: 返回值类型 函数名 (数据类型){}

(1)
//函数占位参数int
void func(int a, int) {
	cout << "this is func" << endl;
}

int main() {

	func(10,10); //占位参数必须填补,必须补个10来代表后面的占位参数int

	system("pause");

	return 0;
}


(2)
//占位参数也可以有默认参数,那此时后面的main函数调用的时候直接func();即可,不用填补了;
void func(int 10) {
	cout << "this is func" << endl;
}


3、函数重载

作用:函数名可以相同,提高复用性;

(1)函数重载满足条件:

  • 同一个作用域下
  • 函数名称相同
  • 函数参数类型不同  或者 个数不同 或者 顺序不同

注意:  函数的返回值不可以作为函数重载的条件

例如如下代码:

(1)
//函数重载需要函数都在同一个作用域下(目前的是全局作用域)
void func()
{
	cout << "func 的调用!" << endl;//个数不同,一个func是0,一个func (int a)是1
}
void func(int a)
{
	cout << "func (int a) 的调用!" << endl;//类型不同
}
void func(double a)
{
	cout << "func (double a)的调用!" << endl;
}
void func(int a ,double b)
{
	cout << "func (int a ,double b) 的调用!" << endl;//顺序不同
}
void func(double a ,int b)
{
	cout << "func (double a ,int b)的调用!" << endl;
}


int main() {

	func();
	func(10);
	func(3.14);
	func(10,3.14);
	func(3.14 , 10);
	
	system("pause");

	return 0;
}


(2)

//函数返回值(int与void的区分)不可以作为函数重载的条件(因为编译器不能按照返回值来区分函数)
//int func(double a, int b)
//{
//	cout << "func (double a ,int b)的调用!" << endl;
//}

(2)函数重载注意事项

  • 引用作为重载条件
  • 函数重载碰到函数默认参数
//函数重载注意事项

(1)

//1、引用作为重载条件

void func(int &a) //int &a=10不合法,10在常量区;
{
	cout << "func (int &a) 调用 " << endl;
}

void func(const int &a)// const int &a=10合法
{
	cout << "func (const int &a) 调用 " << endl;
}

(2)

//2、函数重载碰到函数默认参数

void func2(int a, int b = 10)//默认参数10
{
	cout << "func2(int a, int b = 10) 调用" << endl;
}

void func2(int a)
{
	cout << "func2(int a) 调用" << endl;
}

int main() {
	
	int a = 10;
	func(a); //调用无const
	func(10);//调用有const

    //func2(10); //碰到默认参数产生歧义,出现二义性,需要避免,因为此时两个都可调用

	system("pause");

	return 0;
}

第三章:类和对象

类的组成部分:

1、成员变量(属性): 类内部可以定义多个成员变量,这些变量表示该类对象的状态或特征。成员变量可以是任何数据类型,可以在类内部直接声明和使用。

2、成员函数(方法): 成员函数定义了对象的行为。类的成员函数可以操作类的成员变量,或者提供对外的功能接口。

3、访问控制符

  • public:公开的,任何地方都可以访问这些成员。

  • private:私有的,只有该类的成员函数可以访问,外部无法直接访问。

  • protected:受保护的,只有该类和其派生类(子类)能够访问。

4、构造函数: 构造函数是一个特殊的成员函数,在创建对象时自动调用,用于初始化对象的成员变量。构造函数的名称与类名相同,没有返回类型。

5、析构函数: 析构函数是另一个特殊的成员函数,当对象销毁时自动调用,用于释放资源。

C++面向对象的三大特性为:=封装、继承、多态=

C++认为=万事万物都皆为对象=,对象上有其属性和行为

例如:

​ 人可以作为对象,属性有姓名、年龄、身高、体重...,行为有走、跑、跳、吃饭、唱歌...

​ 车也可以作为对象,属性有轮胎、方向盘、车灯...,行为有载人、放音乐、放空调...

​ 具有相同性质的=对象=,我们可以抽象称为=类=,人属于人类,车属于车类

1、封装

(1)封装的意义

封装是C++面向对象三大特性之一

封装的意义:

  • 属性和行为作为一个整体,表现生活中的事物
  • 将属性和行为加以权限控制

封装意义一:

​ 在设计类的时候,属性和行为写在一起,表现事物

语法: class 类名{   访问权限: 属性  / 行为  };

//圆周率
const double PI = 3.14;

//将属性和行为作为一个整体,用来表现生活中的事物
//类中的属性和行为 统称为 成员
//属性 == 成员属性/成员变量
//行为 == 成员函数/成员方法

//封装一个圆类,求圆的周长
//class代表设计一个类,后面跟着的是类名
class Circle//类名
{
public:  //访问权限  公共权限

//属性
	int m_r;//半径

//行为
	//获取到圆的周长
	double calculateZC()
	{
		return  2 * PI * m_r;
	}
};

int main() {

	//通过圆类,创建圆的对象
	Circle c1;//(实例化)通过一个类Circle,创建一个对象c1的过程
	c1.m_r = 10; //给圆对象的半径 进行赋值操作
	cout << "圆的周长为: " << c1.calculateZC() << endl;
	system("pause");

	return 0;
}

封装意义二

类在设计时,可以把属性和行为放在不同的权限下,加以控制

访问权限有三种:

  1. public        公共权限
  2. protected   保护权限
  3. private       私有权限
//三种权限(成员函数、成员变量都有权限,都有属性)
//公共权限  public     成员 类内可以访问  类外可以访问
//保护权限  protected       类内可以访问  类外不可以访问  儿子可访问父亲的保护权限(汽车等)
//私有权限  private         类内可以访问  类外不可以访问  儿子不可访问父亲的私有权限(银行卡密码等)

class Person
{
	//姓名  公共权限
public:
	string m_Name;

	//汽车  保护权限
protected:
	string m_Car;

	//银行卡密码  私有权限
private:
	int m_Password;

public:
	void func()
	{
		m_Name = "张三";
		m_Car = "拖拉机";
		m_Password = 123456;
	}
};  //类内


int main() {     //;类外

    //实例化具体对象
	Person p;
	p.m_Name = "李四";
	//p.m_Car = "奔驰";  //保护权限类外访问不到
	//p.m_Password = 123; //私有权限类外访问不到
      
    //p.func();//public可访问
	system("pause");

	return 0;
}

(2)struct和class区别

struct 是用于定义一个结构体(structure)的关键字。结构体是一个用户自定义的数据类型,它允许将不同类型的数据组合在一起,形成一个复合数据类型。结构体通常用于表示具有不同属性的实体。

在 C++ 中,class 是用于定义对象类型的关键字。通过类可以封装数据和功能,使得代码更加模块化和可重用。

在C++中 struct和class唯一的区别就在于 默认的访问权限不同

区别:

  • struct 默认权限为公共
  • class   默认权限为私有
class C1
{
	int  m_A; //默认是私有权限
};

struct C2
{
	int m_A;  //默认是公共权限
};

int main() {

	C1 c1;
	c1.m_A = 10; //错误,访问权限是私有

	C2 c2;
	c2.m_A = 10; //正确,访问权限是公共

	system("pause");//

	return 0;
}

(3)成员属性设置为私有

优点1:将所有成员属性设置为私有,可以自己控制读写权限

优点2:对于写权限,我们可以检测数据的有效性

(读:别人可读,可看见;写:该变量可以被修改)

权限(Read):

  • 含义:具有读权限的变量或数据可以被外部查看、读取。也就是说,其他代码可以访问这个变量的值,但不能直接修改它。

  • 示例:在 C++ 或 Java 中,public 修饰的变量通常具有读权限。任何地方都可以读取这个变量的值。

权限(Write):

  • 含义:具有写权限的变量或数据可以被外部修改。也就是说,其他代码可以改变该变量的值。

  • 示例:如果类的成员变量被定义为 public,那么它也可以被外部代码修改,拥有写权限。如果成员变量是 private,那么只有该类的成员函数可以修改它,外部不能直接修改。

class Person {
public:

	//姓名设置可读可写
	void setName(string name) {
		m_Name = name;
	}
    //获取姓名
	string getName()
	{
		return m_Name;
	}


	//获取年龄 只读状态
	int getAge() {
		return m_Age;
	}
	//设置年龄,为了验证数据有效性,设置为可写状态
	void setAge(int age) {
		if (age < 0 || age > 150) {
			cout << "年龄输入有误" << endl;
			return;
		}
		m_Age = age;
	}

	//情人设置为只写
	void setLover(string lover) {
		m_Lover = lover;
	}

private:
	string m_Name; //可读可写  姓名
	
	int m_Age; //只读  年龄

	string m_Lover; //只写  情人
};


int main() {

	Person p;
	//姓名设置
	p.setName("张三");
	cout << "姓名: " << p.getName() << endl;

	//年龄设置
	p.setAge(50);
	cout << "年龄: " << p.getAge() << endl;

	//情人设置
	p.setLover("苍井");
	//cout << "情人: " << p.m_Lover << endl;  //只写属性,不可以读取

	system("pause");

	return 0;
}

2、对象的初始化和清理

  • 生活中我们买的电子产品都基本会有出厂设置,在某一天我们不用时候也会删除一些自己信息数据保证安全
  • C++中的面向对象来源于生活,每个对象也都会有初始设置以及对象销毁前的清理数据的设置。

(1)构造函数和析构函数

  • 对象的初始化和清理也是两个非常重要的安全问题

​         一个对象或者变量没有初始状态,对其使用后果是未知;

        ​ 同样的使用完一个对象或变量,没有及时清理,也会造成一定的安全问题;

  • c++利用了构造函数析构函数解决上述问题,这两个函数将会被编译器自动调用,完成对象初始化和清理工作。
  • 对象的初始化和清理工作是编译器强制要我们做的事情,因此如果我们不提供构造和析构,编译器会提供
  • 编译器提供的构造函数和析构函数是空实现(无内容:表示这些函数没有执行任何操作)。

构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。

构造函数语法:类名( ){ }

  1. 构造函数,没有返回值也不写void
  2. 函数名称与名相同
  3. 构造函数可以有参数,因此可以发生重载
  4. 程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次

析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。

析构函数语法: ~类名(){ }

  1. 析构函数,没有返回值也不写void
  2. 函数名称与名相同,在名称前加上符号  ~
  3. 析构函数不可以有参数,因此不可以发生重载
  4. 程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次
class Person
{
public:
	//1、构造函数
	Person()
	{
		cout << "Person的构造函数调用" << endl;//你写什么就调用什么,没写的话系统自动sc
	}
	
    //2、析构函数
	~Person()
	{
		cout << "Person的析构函数调用" << endl;
	}

};

void test01()
{
	Person p;//未调用构造函数
}

int main() {
	
	test01(); 

	system("pause");

	return 0;
}
//结果会自动调用构造函数,当程序结束前才调用析构函数;

(2)构造函数的分类及调用

两种分类方式:

  • ​ 按参数分为: 有参构造和无参构造
  • ​ 按类型分为: 普通构造和拷贝构造

三种调用方式:

  • ​ 括号法
  • ​ 显示法
  • ​ 隐式转换法
//1、构造函数分类
// 按照参数分类分为 有参和无参构造   无参又称为默认构造函数
// 按照类型分类分为 普通构造和拷贝构造

class Person {
public:
	//无参(默认)构造函数
	Person() {
		cout << "无参构造函数!" << endl;
	}
	//有参构造函数
	Person(int a) {
		age = a;
		cout << "有参构造函数!" << endl;
	}
	//拷贝构造函数
	Person(const Person& p) {
		age = p.age;
		cout << "拷贝构造函数!" << endl;
	}
	//析构函数
	~Person() {
		cout << "析构函数!" << endl;
	}
public:
	int age;
};

//2、构造函数的调用
//调用无参构造函数
void test01() {
	Person p; //调用无参构造函数
}

//调用有参的构造函数
void test02() {

	//2.1  括号法,常用
	Person p1(10);
	//注意1:调用无参构造函数不能加括号;如果加了,编译器认为这是一个函数声明
	//Person p2();  //类似于void func()函数声明
    Person p3(p1);//拷贝构造函数

	//2.2 显式法
	Person p2 = Person(10); //有参构造
	Person p3 = Person(p2); //拷贝构造
	//Person(10)单独写就是匿名对象  当前行结束之后,马上析构(系统会回收掉匿名函数) 

	//2.3 隐式转换法
	Person p4 = 10; // 无参构造,等价于Person p4 = Person(10); 
	Person p5 = p4; // 拷贝构造,等价于Person p5 = Person(p4); 

	//注意2:不能利用 拷贝构造函数 初始化匿名对象 编译器认为是对象声明
	//Person p5(p4);
}

int main() {

	test01();
	//test02();

	system("pause");

	return 0;
}

(2)拷贝构造函数调用时机

C++中拷贝构造函数调用时机通常有三种情况

  • 使用一个已经创建完毕的对象来初始化一个新对象
  • 值传递的方式给函数参数传值
  • 以值方式返回局部对象

(3)构造函数调用规则

默认情况下,c++编译器至少给一个类添加3个函数

1.默认构造函数(无参,函数体为空)

2.默认析构函数(无参,函数体为空)

3.默认拷贝构造函数,对属性进行值拷贝

构造函数调用规则如下:

  • 如果用户定义有参构造函数,c++不在提供默认无参构造,但是会提供默认拷贝构造
  • 如果用户定义拷贝构造函数,c++不会再提供其他构造函数

(4)深拷贝与浅拷贝

深浅拷贝是面试经典问题,也是常见的一个坑

浅拷贝:简单的赋值拷贝操作

深拷贝:在堆区重新申请空间,进行拷贝操作

总结:如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题


第三阶段:C++提高编程(剩余部分在文件提高编程中)

第一章 模板


第二章 STL初识


第三章 STL- 常用容器

注:素材来源于黑马程序员C++第二章-23_变量的作用域_哔哩哔哩_bilibili16 类和对象-封装-属性和行为作为整体_哔哩哔哩_bilibili

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐