本笔记参考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.构造函数的分类以及调用
①分类:
按参数分:有参构造和无参构造
按类型分:普通构造和拷贝构造
三种调用方式:
括号法
显示发
隐式转换法