hdhx的C++笔记

本笔记参考b站黑马视频

有任何错误都欢迎大家指正和批评。

1.注释

        ①单行注释

//

        ②多行注释/* */

/*注释内容 */

2.变量

           给一段指定的内存起名

           意义:方便我们管理内存空间

语法:
     数据类型 变量名 = 变量初始值;
     int a = 10;

3.常量

        记录程序中不可更改的数据。

        ①宏常量

#define 常量名 常量值

#define day 7

        ②const  这种定义方式与变量定义相似,但区别是定义之后的值不能再被修改。

const 数据类型 变量名 = 常量值;

 4.关键字/标识符

        C++中预先保留的单词

        标识符命名规则:

         ①不可以是关键字

         ②只能由字母数字下划线组成

         ③第一位必须是字母或下划线

5.整型 int

        给变量分配合适的内存空间

        不同的数据类型所占用的空间不同,取值范围不同(

               Eg:短整型 short 2字节 -2^15-2^15-1

                    整型   int   4字节                31     31

6.sizeof()

求数据类型占用内存大小的函数

语法:
     sizeof(数据类型)
        或
     sizeof(变量)

7.浮点型float

类型:

    单精度:float    4   7位有效数字

   双精度:double  8   15-16位有效数字

   注:默认情况下,编译器会把小数当成双精度double,可以在数字后加f转换成float

   Eg:3.14f

  注:默认情况下输出一个小数,会显示出六位有效数字。如果想多显示,需要额外配置

8.5科学计数法

   3e2 = 3*10^2
   3e-2=3*10^-2

9.字符型char

   语法:
       char 变量名 =  '字符';

注意:字符型变量只能用来存储一个字符,不能存储字符串

        占用1字节

        存储:字符型变量并不是把字符本身放到内存中存储,而是存储相应的ASCII码

10.转义字符

   用于表示一个不能显示出来的ASCII字符

   Eg:\n 换行

11.字符串型string

   C语言风格 char 变量名[] = “字符串”

   C++       string 变量名 = “字符串”  要包含string头文件

12.布尔类型bool

      真或假

      0代表假

      其余数都代表真

   Bool 变量名 = true或者false;

13.数据的输入

   Cin >> 变量

14.运算符

   ①%取余运算

   ②++递增运算符

   ③- -递减运算符

   ④!非 &&与 ||或

   ⑤三目运算符     

 语法:
      表达式1?表达式2:表达式3

      c=(a > b ? a : b);

   注:递增递减运算符分前置后置

   ++a会先让变量+1,在进行表达式的计算

   a++会先进行表达式的计算,在让变量+1

15.程序流程结构

    顺序结构、选择结构、循环结构

16.switch语句

   表达式只能是整型或字符型

语法:
     switch(表达式)
     {
        Cause 结果1:
        执行语句1;
        Break;
        /*
        中间判断语句和结果语句
        */
        Default:
        执行语句n;
        Break;
     }
 

注:表达式符合‘结果’的时候执行语句,

        表达式都不符合所列写的结果的时候,执行最后的default

17.随机数函数

          生成0-99的随机数

        伪随机数:

    Rand()%100;

注:这样生成的是伪随机数,因为每一次的随机数都是固定的

       真随机数: 在上面的基础上添加这两行

#include<ctime>
srand(unsigned int)time(NULL)

18.数组

        一个集合,用于存放相同数据类型的数据

        ①定义:

语法:
     数据类型 数组名 [数组长度];
     数据类型 数组名 [数组长度] = {值};
     数据类型 数组名 = {值};

        ②特点:放在一块连续的内存空间中,数组中每个元素都是相同的数据类型。

        注意:定义数组的时候必须有初始长度

                    如果在初始化数据时没有全部填写会用0来填补剩余数据

eg:int arr[5]

        ③数组名

         1.可以来统计整个数组在内存中的长度 :利用sizeof函数

#include<iostream>
using namespace std;
int main()
{
	int arr[10];
	cout << "整个数组占用的空间:" << sizeof(arr) << endl;
	cout << "每个元素占用的空间:" << sizeof(arr[0]) << endl;
	cout << "数组中元素的个数:" << sizeof(arr)/sizeof(arr[0]) << endl;
}

         2.可以获取数组在内存中的首地址。

#include<iostream>
using namespace std;
int main()
{
	int arr[10];
	cout << "数组的首地址:" << arr << endl;
}

        注:数组名是一个常量,不可进行赋值操作

19. 案例:5只小猪称体重

        本质:五个数字排大小

        思路:先设定一个最大值,然后用数组中的每一个数字去和最大值进行一个比较,更新最大值。

        用while循环写:

#include<iostream>
using namespace std;
int main()
{
	int arr[5] = { 300,350,400,370,280};
	int max = 0;
	int i = 0;
	while (i < 5)
	{
		if (arr[i] > max)
		{
			max = arr[i];
		}
		i++;
	}
	cout << "最大值为" << max << endl;
}

错误日志:声明数组的时候,不同数字要用  “,”  分隔

        用for循环写:

#include<iostream>
using namespace std;
int main()
{
	int arr[5] = { 300,350,400,370,280};
	int max = 0;
	for(int i = 0 ;i<5 ;i++)
	{
		if (arr[i] > max)
		{
			max = arr[i];
		}
		i++;
	}
	cout << "最大值为" << max << endl;
}

错误日志:for循环中的格式用  “;”

20.案例:数组元素逆置

描述:声明一个五个元素的数组,并将元素逆置

#include<iostream>
using namespace std;
int main()
{
	int arr[5] = { 300,350,400,370,280};
	int arr2[5];
	int i = 0;
	int j = 0;
	while (i < 5)
	{
		int j = 4 - i;
		arr2[j] = arr[i];
		i++;
	}
	cout << "数组逆序输出为"  << endl;
	for (j = 0;j < 5;j++)
	{
		cout << arr2[j] << endl;
	}
}

错误笔记:①j的运算规则应该是4-i

                    ②并且j的运算语句一定要在循环体内,否则是一个固定的数字,起不到标号的作用。

优化:

          j写成4-i不太好,因为只是针对5个元素的数组这一种情况

#include<iostream>
using namespace std;
int main()
{
	int arr[5] = { 300,350,400,370,280};
	int arr2[5];
	int i = 0;
	int j = 0;


	while (i < 5)
	{
		int j = sizeof(arr)/sizeof(arr[0])-1 - i;
		arr2[j] = arr[i];
		i++;
	}
	cout << "数组逆序输出为"  << endl;

	for (j = 0;j < 5;j++)
	{
		cout << arr2[j] << endl;
	}
}

实现版本2

思路:只用一个数组来来回折腾,缺点是思路稍微麻烦一点,而且需要一个变量来作为“中间人”

#include<iostream>
using namespace std;
int main()
{
	int arr[5] = { 300,350,400,370,280};
	int start = 0;
	int temp = 0;

	while (start < 3)
	{
		int end = 0;
		end = sizeof(arr) / sizeof(arr[0]) - 1 - start;
		temp = arr[start];
		arr[start] = arr[end];
		arr[end] = temp;
		start++;
		
	}
	cout << "输出逆序后的数组" << endl;
	for(int j = 0;j<5;j++)
	{
		cout << arr[j] << endl;

	}
}

错误笔记:①再一次把end的更新规则放在循环体外了

                    ②循环只能执行三次,执行五次的话就是调换了两遍。 

21.案例:冒泡排序

思路:每次冒出数组中的最大值,实现的的方法就是让左边的数和右边的数进行比较,如果左大于右就交换。重复执行这个算法,就能逐一筛选出最大值的降序排列。

#include<iostream>
using namespace std;
int main()
{
	int arr[9] = {4,2,8,0,5,7,1,3,9};
	int i = 0;
	int j = 0;
	int temp = 0;
	int n = 0;
    //开始冒泡排序
	while (n < 8)
	{
        //内层循环对比
		while (i < 8)
		{
			if (arr[i] > arr[i + 1])
			{
				temp = arr[i];
				arr[i] = arr[i + 1];
				arr[i + 1] = temp;
			}
			i++;
		}
		i = 0;
		n++;
	}
	cout << "输出逆序后的数组" << endl;
	for(int j = 0;j<9;j++)
	{
		cout << arr[j] << endl;

	}
}

优化:存在的问题是每次都对比8次,因为最后面的一个数已经是最大的了,在下一次不需要排序了。

		while (i < 8-n)

改成这样就可以了。 

22.二维数组

        ①定义方式

用四种种方法声明三行四列的二维数组	
int arr[3][4];
/*直接赋值的定义方法 */
int arr2[2][3] = 
{
    {1,2,3},
    {4,5,6}
};

int arr3[2][3] = {1,2,3,4,5,6};

int arr[][4]={1,2,3,4}

       注意 :在定义二维数组的时候可以省略行数,但是列数不可以省略。

                        第四种方法只声明列数 

       打印二维数组用双层for循环 

#include<iostream>
using namespace std;
int main()
{
	int arr[2][3];
	arr[0][0] = 1;
	arr[0][1] = 2;
	arr[0][2] = 3;
	arr[1][0] = 4;
	arr[1][1] = 5;
	arr[1][2] = 6;
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			cout << arr[i][j] << endl;
		}
	}
}

23.二维数组名

        可以用来查看数组所占用的内存空间

        可以用来查看二维数组的首地址

        与一维数组的用途一样

①查看数组所占用的空间    4*6 = 24(整型占4字节)

#include<iostream>
using namespace std;
int main()
{
	int arr[2][3] = 
	{
		{1,2,3},
		{4,5,6}
	};

	cout << sizeof(arr) << endl;
}

 ②二维数组第一行所占用空间

#include<iostream>
using namespace std;
int main()
{
	int arr[2][3] = 
	{
		{1,2,3},
		{4,5,6}
	};

	cout << sizeof(arr[0]) << endl;
}

注意:在二维数组中arr[0]代表第一行的所有数据

③查看二维数组的首地址

	cout << arr<< endl;
	cout << int(arr) << endl;

24.案例:考试成绩统计

描述:三名同学的考试成绩如下,输出总成绩

#include<iostream>
using namespace std;
int main()
{
	int arr[3][3] = {
		{100,100,100},
		{90,50,100},
		{60,70,80}
	};
	int sum1 = 0;
	for (int i = 0; i < 3;i++)
	{
		sum1 = arr[i][0] + arr[i][1] + arr[i][2];
		cout <<"第"<<i+1<<"个人的总分为" << sum1 << endl;
		sum1 = 0;
	}
}

25.函数

①定义

返回值类型 函数名 参数表列 函数体语句 return表达式

语法:
    返回值类型 函数名( 参数列表)
    {
        函数体语句;
        return 表达式;
    }

②调用

说明:函数调用里面的参数叫形式参数,简称形参

 在函数定义的时候,形式参数并没有真实数据,在函数调用的时候,实参的值会传递给形参

③值传递

做值传递的时候,函数形参发生改变,并不会影响实参。

④函数的常见样式

无参无返

#include<iostream>
using namespace std;

void test01()
{
	cout << "hello world";
}
int main()
{
	test01();
}

有参无返

#include<iostream>
using namespace std;

void test02(int a )
{
	cout << "hello world"<<a;
}
int main()
{
	test02(100);
}

无参有返

#include<iostream>
using namespace std;

int test03()
{
	cout << "hello world";
	return 1000;
}
int main()
{
	int num1 = test03();
	cout << num1;
}

有参有返

#include<iostream>
using namespace std;

int test04(int a)
{
	cout << "hello world"<<a<<endl;
	return 1000;
}
int main()
{
	int num1 = test04(100);
	cout << num1<<endl;
}

⑤函数的声明

#include<iostream>
using namespace std;
//函数声明的意义:提前告诉编译器函数的存在
int max(int a, int b);

int main()
{
	cout<<max(20, 30);

}
int max(int a, int b)
{
	return a > b ? a : b;
}

注意:函数在main函数之后,必须要声明。并且函数声明可以有多次,但是定义只能有一次。

⑥函数的分文件编写

        1.创建后缀名为.h的头文件         3.在头文件中写函数的声明

创建swap.h文件并如下代码
void swap(int a, int b);

        2.创建后缀名为.cpp的源文件             4.在源文件中写函数的定义

为了声明和swap.h文件是配套的需要include swap.h
#include"swap.h"
#include<iostream>
using namespace std;
void swap(int a, int b)
{
	int temp = a;
	a = b;
	b = temp;
	cout << a << endl << b;
}

      5.在原来的文件中引用

#include<iostream>
using namespace std;
#include"swap.h"
int main()
{
	swap(20, 30);

}

26.指针

指针声明三部曲,声明 变量,声明 指针,建立指针和变量之间的关系。

    可以通过指针间接访问内存

    指针就是地址

    ①如何定义指针

语法:

数据类型 * 指针变量名
int * p;

    让指针记录变量a的地址

P = &a;

   取址符号,让p记录a的地址

  ②怎么使用指针

可以通过解引用的方式来找到指针指向的内存

指针前加*代表解引用,找到指针指向的内存中的数据

*p=a

也可以有这种写法

这种写法更加简洁,相当于*是声明指针,p=&a表示p取a的地址。
int *p=&a;

③指针所占内存空间

   指针存的是地址,和什么类型的指针没关系

  在32位操作系统下占用4个字节,64   8

#include<iostream>
using namespace std;
#include"swap.h"
int main()
{
	int a = 10;
	int* p;
	p = &a;
	double b = 2;
	double* p2;
	p2 = &b;
	cout << sizeof(p2) << endl;
	cout << sizeof(p) << endl;
}

④空指针

指向编号为0的空间的指针

 一般用于初始化指针,

空指针指向的编号为0的空间是不能访问的

0到255之间的内存编号是系统占用的,不可以访问。

int * p = NULL;

⑤野指针

指针变量指向非法的内存空间

int * p = (int * )0X1100;

(int*)就是把这个16进制的数强行转换成地址

  在程序中要避免野指针

⑥const修饰指针

   三种情况:

   ①Const修饰指针:常量指针

const int * p = &a;
#include<iostream>
using namespace std;
#include"swap.h"
int main()
{
	int a = 10;
	const int* p = &a;
	p = NULL;
	cout << p;
}

指针的指向可以修改,指针指向的值不可以修改。

   ②const修饰常量,指针常量(const直接修饰指针,指针的指向不能修改)

int * cosnt p = &a;
#include<iostream>
using namespace std;
int main()
{
	int a = 10;
	int * const p = &a;
	*p = 20;
	cout << a;
}

指针的指向不可以修改,但指针指向的值可以修改

   ③const即修饰指针又修饰常量

const int * const p = &a;

指针的指向和指针指向的值都不可以修改。

27.指针和数组

利用指针访问数组中的元素。

#include<iostream>
using namespace std;
int main()
{
	int arr[] = {1,2,3,4,5,6};
	//arr就是数组的首地址
	int* p = arr;
	//输出数组中的第一个元素
	cout << *p << endl;
	cout << "arr数组的首地址是" << p << endl;
	//让指针向后偏移四个字节,因为指针是int型
	p = p + 1;
	cout << "arr数组的第二个元素的地址是" << p << endl;
	cout << *p << endl;
}

QUESTION:为什么p+1之后就能神奇的对应到第二个元素?为什么p+1之后对应的地址增加了4?

ANSWER:因为是整形指针,++之后往后偏移四个字节。

用for循环实现用指针遍历数组

#include<iostream>
using namespace std;
int main()
{
	int arr[] = {1,2,3,4,5,6};
	//arr就是数组的首地址
	int* p = arr;
	//输出数组中的第一个元素
	for (int i = 0; i < 6; i++)
	{
		cout << "第" << i + 1 << "个元素的地址是" << p<<endl;
		cout << "第" << i + 1 << "个元素的值是" << *p<<endl;
		p++;
	}
}

28.指针和函数

①值传递(复习)

#include<iostream>
using namespace std;
void swap01(int a, int b)
{
	int temp = a;
	a = b;
	b = temp;
	cout << "函数中的形式参数" << "a=" << a << endl <<"b=" << b << endl;
}
int main()
{
	int a = 10;
	int b = 20;
	swap01(a, b);
	cout << "实际参数" <<"a=" << a << endl <<"b=" << b << endl;
}

②地址传递

神奇之处在于,能够通过函数把实参的值变了。

#include<iostream>
using namespace std;
void swap02(int* a, int* b)
{
	//相当于就是把a,b的地址换了
	int temp = *a;
	*a = *b;
	*b = temp;

}
int main()
{
	int a = 10;
	int b = 20;
	swap02(&a, &b);
	cout << "实际参数" <<"a=" << a << endl <<"b=" << b << endl;
}

 29.指针配合数组和函数的案例

案例描述:封装一个函数,利用冒泡排序,实现对整型数组的升序排序

#include<iostream>
using namespace std;
void bubbleSort(int * arr,int len)
{
	for (int i = 0; i < len-1; i++)
	{
		for (int j = 0; j < len -1- i; j++)
		{
			if (arr[j] >arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}
int main()
{
	int arr[] = { 6,5,4,3,2,1 };
	int len = sizeof(arr) / sizeof(arr[0]);
	bubbleSort(arr,len);
	for (int i = 0; i < len ; i++)
	{
		cout << arr[i] << endl;
	}
}

注意:在把数组传进函数里时只需要传数组的首地址即可

30.结构体

用途:可以创建自定义的数据类型,允许用户存储不同的数据类型

其实自定义的数据类型就是一些集合组成的一个类型

①定义

1.
struct 结构体名 变量名
2.
struct 结构体名 变量名 ={成员1值,成员2值,...}
3.
定义结构体时顺便创建变量

 ②使用

方法1.
	struct Student s1;
	s1.name = "张三";
	s1.age = 13;
	s1.score = 100;
方法2
	struct Student s1 = {"张三",13,100};
方法3.
在定义结构体的时候顺便创建
#include<iostream>
using namespace std;

//创建学生数据类型
struct Student
{
	//成员列表
	//姓名
	string name;
	//年龄
	int age;
	//分数
	int score;
}s3;
int main()
{

	s3.name = "翠花";
	s3.age = 15;
	s3.score = 100;
	cout << s3.name << endl;

}

注意:在调用结构体的时候struct关键字可以省略。

31.结构体数组

将自定义的结构体放在数组中方便维护。

①定义

struct 结构体名 数组名[]={{}, {},{}...}
	struct Student stuArray[3] =
	{
		{"张三",18,100},
		{"李四",28,99},
		{"王五",38,98}
	};
	stuArray[2].score = 96;

②遍历结构体数组

int main()
{
	struct Student stuArray[3] =
	{
		{"张三",18,100},
		{"李四",28,99},
		{"王五",38,98}
	};
	stuArray[2].score = 96;

	cout << stuArray[2].score << endl;
	for (int i = 0; i < 3; i++)
	{
		cout << "姓名" << stuArray[i].name << endl;
		cout << "年龄" << stuArray[i].age << endl;
		cout << "分数" << stuArray[i].score<< endl;
	};

}

32.结构体指针

利用操作符  ->  可以用过结构体指针访问结构体属性

对于结构体来说直接用   就可以访问属性

但是对于结构体指针,要用->

int main()
{
	Student s1 = {"翠花",10,66};
	Student* p = &s1;
	cout << "姓名" << p->name << "年龄" << p->age;
}

33.结构体嵌套结构体

被嵌套的结构体要先声明。

#include<iostream>
using namespace std;

//创建学生数据类型
struct gfriend
{
	string name;
	int age;

};
struct Student
{
	//成员列表
	//姓名
	string name;
	//年龄
	int age;
	//分数
	int score;
	struct gfriend g1;
};
int main()
{
	Student s1 = {"翠花",10,66};
	s1.g1.age = 15;
	s1.g1.name = "西西";
	cout << "姓名" << s1.g1.age << "年龄" << s1.g1.name;
}

34.结构体做函数参数

将结构体作为参数向函数中传递。

值传递

地址传递

#include<iostream>
using namespace std;
struct Student
{
	string name;
	int age;

};
void printStu(Student p)
{
	//值传递
	cout << p.name << endl << p.age;
}
void printStu2(Student *p)
{
	//地址传递
	cout << p->name << endl << p->age;
}
int main()
{
	Student s1;
	s1.name = "张三";
	s1.age = 18;
	printStu2(&s1);
};

注意:与前面相同,值传递不会修改实参,地址传递会修改实参。

35.结构体中const的使用

 用来防止误操作。

36.结构体案例

案例描述:学校做毕设项目,每名老师带五个学生,总共三个老师,需求如下,设计老师和学生的结构体,其中在老师的结构体中,有老师姓名和一个存放五名学生的数组作为成员。学生的成员有姓名、老师分数,创建数组存放三名老师,通过函数给每个老师及所带的学生赋值,最后打印老师数据以及老师所带的学生数据。

37.内存四区

①代码区

存放函数体的二进制代码,由操作系统将进行管理。

写的所有代码都放在里面,程序运行前,在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域。代码区:存在CPU执行的机器指令(就是咱们自己写的代码),代码区的特点:共享:对于频繁被执行的程序,只需要在内存中有一份代码。只读:防止程序意外地修改他的指令。

②全局区:存放全局变量和静态变量以及常量

生成的时间与代码区相同。

存放全局变量、静态变量、常量(字符串常量 和 全局常量)。

③栈区:

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

函数调用之后内存就释放掉了

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

④堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收

不同区域存放的数据,赋予不同的生命周期。

#include<iostream>
using namespace std;
int * func()
{
	//利用new关键字将数据开辟到堆区,并且返回内存地址。
	int* p = new int(10);
	return p;
}
int main()
{
	int* p = func();
	cout << *p << endl;
}

38.new操作符

#include<iostream>
using namespace std;
int * func()
{
	//利用new关键字将数据开辟到堆区,并且返回内存地址。
	int* p = new int(10);
	return p;
}
void test01()
{
	int* p = func();
	cout << *p << endl;
	delete p;
	cout << *p << endl;
}
void test02()
{
	int * arr = new int[10];//代表数组有10个元素,返回空间首地址
	for (int i = 0; i < 10; i++)
	{
		arr[i] = i + 100;//给十个元素赋值

	}
	for (int i = 0; i < 10; i++)
	{
		cout << arr[i] << endl;
	}
	//释放堆区数组
	delete[] arr;
}
int main()
{
	test02();
}

39.引用

作用:给变量起别名

语法:

数据类型 &别名 = 原名
#include <iostream>
using namespace std;
int main()
{
	int a = 10;
	int& b = a;
	b = 20;
	cout << a;
}

注意事项:

1.引用必须要初始化

2.引用一旦初始化后,就不可以更改了。

40.引用做函数参数

引用传递 形参会修饰实参

#include <iostream>
using namespace std;
void myswap01(int a, int b)
{
	int tempt = a;
	a = b;
	b = tempt;
}
void myswap02(int *a, int *b)
{
	int tempt = *a;
	*a = *b;
	*b = tempt;
}
void myswap03(int &a, int& b)
{
	int tempt = a;
	a = b;
	b = tempt;
}
int main()
{
	cout << "zhichuandi"<<endl;
	int a = 10;
	int b = 20;
	myswap01(a, b);
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
	cout << "dizhichuandi"<<endl;
	int c = 10;
	int d = 20;
	myswap02(&c, &d);
	cout << "a=" << c << endl;
	cout << "b=" << d << endl;
	cout << "yinyongchuandi" << endl;
	int e = 10;
	int f = 20;
	myswap03(e, f);
	cout << "a=" << c << endl;
	cout << "b=" << d << endl;
	
}

41.引用做函数的返回值

不要返回局部变量的引用

函数的调用可以作为左值

42.引用的本质

引用的本质是一个指针常量

43.常量引用

修饰形参,防止误操作

正常来说
int &ref=10;
是不可以正常使用的,因为引用不能引用一个常数。
但是下面的语句可以
const int &ref=10;
这里相当于编译器帮我们修改了代码,
int tempt=10;
const int&ref = tempt;

44.函数提高

①函数的默认参数

如果传参数的话就用传的参数,如果没传参数就用默认值。

#include <iostream>
using namespace std;
int func(int a, int b=20, int c=30)
{
	return a + b + c;
}
int main()
{
	cout << func(10) << endl;
	cout << func(10, 30) << endl;
}

注意事项:

如果某个位置已经有了默认参数,那么从这个位置往后,从左到右都必须有默认值。

如果函数声明有默认参数,函数实现就不能有默认参数,声明和实现智能有一个有默认参数。

②函数占位参数

 ③函数重载

i)概述

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

条件: 同一个作用域下,函数名相同,函数参数类型不同或者个数不同或者顺序不同。

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

#include <iostream>
using namespace std;
void func()
{
	cout << "func的调用" << endl;

}
void func(int a )
{
	cout << "func(int a )的调用" << endl;
}
int main()
{
	func();
	func(10);
}

ii)函数重载的注意事项。

引用作为重载的条件

#include <iostream>
using namespace std;
void func(int &a)
{
	cout << "func(int a )的调用" << endl;

}
void func(const int &a)
{
	cout << "func(const int a )的调用" << endl;

}

int main()
{
	int a = 10;
	func(10);
	func(a);
}

函数重载碰到默认参数

会报错,写函数重载尽量不要用默认参数
#include <iostream>
using namespace std;
void func(int a,int b=10)
{
	cout << "func(int a )的调用" << endl;

}
void func(int a)
{
	cout << "func(const int a )的调用" << endl;

}

int main()
{
	int a = 10;
	func(10);
}

45.类和对象 important

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

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

①封装

#include <iostream>
using namespace std;
//设计一个圆类,求球的周长。
//周长公式:2*PI*RADIUS
//class代表设计一个类,类后面紧跟着就是类名称
class circle
{
	//访问权限 公共权限
public:
	//属性
	int m_r;
	int PI = 3.1415;
	//行为
	//获取圆的周长
	double calculateZC()
	{
		return 2 * PI * m_r;
	}
};
int main()
{
	//通过一个圆类创建一个具体的圆
	circle C1;
	C1.m_r = 10;
	cout << "圆的周长为" << C1.calculateZC() << endl;
}

实例化:通过一个类创建一个对象的过程。

类中的属性和行为统一称为成员。

属性也叫作成员属性、成员变量。

行为也叫成员函数、成员方法。

②封装的意义。

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

访问权限有一下三种:

public 公共权限      成员类内可以访问,类外可以访问

protected 保护权限  成员类内可以访问,类外不可以访问(父类中的保护权限子类也可以访问)

private 私有权限    类内可以访问 类外不可访问(父类中的私有权限子类不能访问)

注意:代码会报错
#include<iostream>
using namespace std;
class Person
{
public:
	string name;
protected:
	string car;
private:
	int password;
public:
	void func()
	{
		string name = "zhangsan";
		car = "拖拉机";
		password = 12345;

	}
};
int main()
{
	Person P1;
	P1.car = "奔驰";//这里注意,car是private属性,所以在类外不能访问,只能在类内调用。
}

 ③class 和 struct的区别

struct默认权限是公共public

class默认权限是private

注意代码会报错
#include<iostream>
using namespace std;
class test {
	int a = 100;
};
int main()
{
	test A;
	A.a = 1000;//这里就会报错因为class 默认权限是private,不能直接调用
}

④将成员属性设置为私有

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

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

#include<iostream>
using namespace std;
#include<string>
class Person
{
public:
	//在公共的成员函数中为private属性赋值
	//写姓名 设置
	void setname(string name)
	{
		m_name = name;
	}
	string getname()
	{
		return m_name;
	}
	void setage(int age)
	{
		if (age < 0 || age>150)
		{
			
			cout << "你这个老妖精" << endl;
			return;
		}

		m_age = age;
	}
	int getage()
	{
		return m_age;
	}
private:
	string m_name; //可读可写
	int m_age;     //可读可写,但是年龄的范围必须是0-150之间
	string lover;//只写
};
int main()
{
	Person zhangsan;
	zhangsan.setname("张三");
	cout << zhangsan.getname() << endl;
	zhangsan.setage(10);
	cout << zhangsan.getage() << endl;
}

46.案例

    /*
    * 利用成员函数判断
    * 
    * 对于成员函数写法的理解,
    * 为什么只需要传一个实例就可以呢?
    * 因为在类中,本身相当于定义了一个类,在这个类中我可以访问private的属性,但是新传进来的C相当于在这个类之外另建了一个类,这个类就只能调用public的方法来使用。
    */

对于成员函数的使用还是有一点小弯的。

#include<iostream>
using namespace std;
//设计一个立方体类
//求出立方体的面积和体积
//分别用全局函数和成员函数判断两个立方体是否相等。
class CUBE
{
private:
	double m_l;
	double m_w;
	double m_h;
public:
	
	void setparma(double l, double h, double w)
	{
		m_l = l;
		m_h = h;
		m_w = w;
	}
	double get_l()
	{
		return m_l;
	}
	double get_h()
	{
		return m_h;
	}
	double get_w()
	{
		return m_w;
	}
	double get_cube_S()
	{
		return 2 * (m_l * m_w + m_l * m_h + m_w * m_h);
	}
	double get_cube_V()
	{
		return (m_l * m_w * m_h);
	}
	/*
	* 利用成员函数判断
	* 
	* 对于成员函数写法的理解,
	* 为什么只需要传一个实例就可以呢?
	* 因为在类中,本身相当于定义了一个类,在这个类中我可以访问private的属性,但是新传进来的C相当于在这个类之外另建了一个类,这个类就只能调用public的方法来使用。
	*/
	bool judgeCube2(CUBE &C)
	{
		if (m_h == C.m_h && m_l == C.m_l && m_w == C.m_w)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

};

/*
利用全局函数判断两个CUBE是否相等

*/
bool judgeCUBE(CUBE &c1, CUBE &c2)   //引用传递
{
	if (c1.get_h() == c2.get_h() && c1.get_l() == c2.get_l() && c1.get_w() == c2.get_w())
	{
		return true;
	}
}
int main()
{
	CUBE C1;
	C1.setparma(10, 10, 10);
	cout << C1.get_cube_S() << endl;
	cout << C1.get_cube_V() << endl;
	CUBE C2;
	C2.setparma(10, 10, 10);
	bool ret= judgeCUBE(C1, C2);
	if (ret)
	{
		cout << "c1和c2相等"<<endl;
	}
	else
	{
		cout << "c1和c2不相等"<<endl;
	}
	bool ret2 = C1.judgeCube2(C2);
	if (ret2)
	{
		cout << "通过成员函数判断的结果为C1和C2相等"<<endl;
	}
	else
		cout << "通过成员函数判断为C1和C2不相等"<<endl;
}	

47.案例2

48.对象的初始化和清理

每个对象都有初始设置以及对象销毁前数据的设置

①构造函数和析构函数

编译器自动调用,完成对象初始化和清理工作

但是编译器提供的构造函数和析构函数是空实现。

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

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

②语法

构造函数: 类名(){}

        构造函数是没有返回值的,也不需要写void

        函数名和类名相同

        构造函数可以有参数,因此也可以使用 重载技术

        程序在调用对象的时候会自动调用构造,无需手动调用。

#include<iostream>
using namespace std;
class Person
{
public:
	Person()
	{
		cout << "Person构造函数的调用";
	}
};
void test01()
{
	Person p;
}
int main()
{
	test01();
}

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

        析构函数没有返回值,也不写void

        函数名称与类名称相同,多加一个~

        析构函数不可以有参数,因此无法使用重载技术

        在对象销毁前会自动调用析构函数,无需手动调用,而且只会调用一次

#include<iostream>
using namespace std;
class Person
{
public:
	/*
	* 构造函数的使用
	*/
	Person()
	{
		cout << "Person构造函数的调用"<<endl;
	}
	/*
	* 析构函数的使用
	*/
	~Person()
	{
		cout << "析构函数的使用"<<endl;
	}
};
void test01()
{
	Person p;//相当于一个局部变量,所以是栈上的数据,test01执行完毕之后就会释放这个对象。
}
int main()
{
	Person C;
	system("pause");
}

        

49.构造函数的分类以及调用

①分类:

按参数分:有参构造和无参构造

按类型分:普通构造和拷贝构造

三种调用方式:

        括号法

        显示发

        隐式转换法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值