编写一个C++程序分为4个步骤
# include<iostream>
using namespace std;
int main() {
cout << "hello world" << endl;
system("pause");
return 0;
}
作用;方便我们管理内存空间 变量创建的语法: 数据类型 变量名= 变量初始值
作用:用于记录程序中不可更改的数据 C++定义常量的两种方法:
# include<iostream>
using namespace std;
//#define宏常量
#define Day 7
int main() {
cout << "一周有" << Day << "天" << endl;
int a = 10;
//const修饰的变量
const double pi = 3.14;
cout << "圆周率为" << pi << endl;
cout << "hello world " << "a = " << a << endl;
system("pause");
return 0;
}
不要用关键字给变量或者变量起名称
作用:C++规定给标识符(变量,常量)命名时有一套自己的规则,和其他编程的规则类似
C++规定在创建一个变量或者常量时,必须要指定相应的数据类型,否则无法给变量分配内存
作用:整型变量表示的是整数类型的数据 C++中可以表示整型有以下几种方式,区别在于所占内存空间不同
#include <iostream>
using namespace std;
int main() {
//整型
//1.短整型(2个字节)
short num1 = 10;
//2.整型(4个字节)
int num2 = 10;
//3.长整型
long num3 = 10;
//4.长长整型
long long num4 = 10;
cout << "num1=" << num1 << endl;
cout << "num2=" << num2 << endl;
cout << "num3=" << num3 << endl;
cout << "num4=" << num4 << endl;
}
作用:利用这个关键字可以统计数据类型所占内存空间大小 语法:sizeof(数据类型/变量) 实例:
#include<iostream>
using namespace std;
int main() {
short num1 = 10;
//sizeof参数既可以传入num1也可以传入short
cout << "num1占用的内存空间为" << sizeof(num1) << endl;
cout << "short占用的内存空间为" << sizeof(short) << endl;
system("pause");
return 0;
}
作用:用于表示小数 浮点型变量分为2种
#include <iostream>
using namespace std;
int main() {
//单精度float
float f1 = 1.f;//注意定义单精度时,多加一个f否则默认双精度
//双精度double
double f2 = 1.;
cout << "f1=" << f1 << " f1占用的空间" << sizeof(f1) << endl;
cout << "f2=" << f2 << " f2占用的空间" << sizeof(f2) << endl;
//科学计数法
float f3 = 3e2;//3*10^2;
float f4 = 3e-2;
cout << "f3= " << f3 << " f4=" << f4 << endl;
}
作用:字符型变量用于显示单个字符 语法:char ch = 'a';
#include<iostream>
using namespace std;
int main() {
//字符变量创建方法
char ch = 'a';
cout << "ch=" << ch << endl;
//字符变量所占内存大小
cout << "ch所占内存大小" << sizeof(ch) << endl;
//字符型变量常见错误
// 不能使用双引号创建字符
//char ch2 = "b";
//单引号里面只能由一个字符
//char ch3 = 'fsfs'
//字符型变量对应的ASCII编码
//a-97
//A-65
cout << (int)ch << endl;
}
作用:用于表示一些不能显示出来的ASCII字符 现阶段常用\\ \n \t
作用:用于表示一串字符 两种风格
int main(){
char str1[] = "hello world";
cout << str1 << endl;
}
注意:C风格的字符串要用双引号括起来 2. C++风格的字符串:string 变量名 = "字符串值"
#include<iostream>
#include<string>//用C++风格的字符串时,需要包含这个头文件
using namespace std;
int main() {
//C风格的字符串
char str[] = "hello world";
cout << str << endl;
//C++风格字符串
string str2 = "hello world2";
cout << str2 << endl;
}
作用:布尔数据类型代表真或假的值 bool类型两个值:true和false,bool类型只占一个字节大小 实例:
#include<iostream>
using namespace std;
int main() {
//创建bool数据类型
bool flag = true;//true代表真
cout << flag << endl;
//查看bool类型所占空间
cout << "bool类型所占的空间为:" << sizeof(flag) << endl;
system("pause");
return 0;
}
作用:用于从键盘获取数据 关键字:cin 语法cin>>变量 实例:
#include<iostream>
#include<string>
using namespace std;
int main() {
//键盘输入语句
//整型
int a = 0;
cout << "请给整型变量a赋值" << endl;
cin >> a;
cout << "整型变量a=" << a << endl;
//浮点型
float f = 3.14;
cout << "请给浮点型变量f赋值:" << endl;
cin >> f;
cout << "浮点型变量f=" << f << endl;
//字符型
char ch = 'a';
cout << "请给字符型变量ch赋值" << endl;
cin >> ch;
cout << "字符型变量ch=" << ch << endl;
//字符串型
string str = "hello";
cout << "请给字符串str赋值" << endl;
cin >> str;
cout << "字符串型变量str=" << str <<endl;
bool flag = false;
cout << "请给布尔类型的flag赋值" << endl;
cin >> flag;
cout << "布尔类型的变量flag=" << flag << endl;
system("pause");
return 0;
}
#include<iostream>
using namespace std;
int main() {
//加减乘除
int a1 = 10;
int b1 = 3;
cout << a1 + b1 << endl;
cout << a1 - b1 << endl;
cout << a1 * b1 << endl;
cout << a1 / b1 << endl;//两个整数相除,结果仍然是整数,将小数部分去除
system("pause");
return 0;
}
#include<iostream>
using namespace std;
int main() {
//前置递增,先变量+1,后进行表达式运算
int a2 = 10;
int b2 = ++a2 * 10;
cout << "a2=" << a2 << endl;
cout << "b2 = " << b2 << endl;
//后置递增,先进行表达式运算,后让变量+1
int a3 = 10;
int b3 = a3++ * 10;
cout << "a3 =" << a3 << endl;
cout << "b3 = " << b3 << endl;
//输出
/*a2=11
b2 = 110
a3 =11
b3 = 100*/
}
作用:用于将表达式的值赋给变量 赋值运算符包括以下几个符号
C/C++支持三种程序运行结构:顺序,选择,循环
#include<iostream>
using namespace std;
int main() {
//选择结构,单行if语句
//用户输入分数,如果分数大于600,视为考上一本大学,在屏幕输出
//用户输入分数
int score = 0;
cout << "请输入一个分数" << endl;
cin >> score;
//打印用户输入的分数
cout << "您输入的分为:" << score << endl;
//判断分数是否大于600
if (score > 600) {//注意if后面千万不能加分号,不然{}里面的判断都是白写了,是否满足都会输出{}里面的结果
cout << "恭喜您考上一本大学" << endl;
}
}
#include<iostream>
using namespace std;
int main() {
//选择结构,单行if语句
//用户输入分数,如果分数大于600,视为考上一本大学,在屏幕输出
//用户输入分数
int score = 0;
cout << "请输入一个分数" << endl;
cin >> score;
//打印用户输入的分数
cout << "您输入的分为:" << score << endl;
//判断分数是否大于600
if (score > 600) {//注意if后面千万不能加分号,不然{}里面的判断都是白写了,是否满足都会输出{}里面的结果
cout << "恭喜您考上一本大学" << endl;
}
else {
cout << "很可惜,你没有考上一本大学" << endl;
}
}
#include<iostream>
using namespace std;
int main() {
//选择结构,单行if语句
//用户输入分数,如果分数大于600,视为考上一本大学,在屏幕输出
//用户输入分数
int score = 0;
cout << "请输入一个分数" << endl;
cin >> score;
//打印用户输入的分数
cout << "您输入的分为:" << score << endl;
//判断分数是否大于600
if (score > 600) {//注意if后面千万不能加分号,不然{}里面的判断都是白写了,是否满足都会输出{}里面的结果
cout << "恭喜您考上一本大学" << endl;
}
else if(score > 400){
cout << "恭喜你考上二本大学" << endl;
}
else {
cout << "很可惜,你没有考上本科" << endl;
}
}
#include<iostream>
using namespace std;
int main(){
int score = 0;
//输入
cout << "请输入分数" << endl;
cin >> score;
if (score > 600){
cout <<"恭喜你考上一本"<< endl;
if (score > 700){
cout << "恭喜你考上北大" << endl;
}else if(score > 650){
cout << "恭喜考上清华" <<endl;
}else{
cout << "恭喜考上人大" <<endl;
}
}else if(score > 500){
cout << "恭喜考上二本" << endl;
}else if(score > 400){
cout << "恭喜考上三本" << endl;
}
}
练习案例,三只小猪称体重,判断谁更重
#include<iostream>
using namespace std;
int main() {
int num1 = 0;
int num2 = 0;
int num3 = 0;
int temp = 0;
//输入三只小猪的体重
cout << "请输入第一只小猪的体重" << endl;
cin >> num1;
cout << "请输入第二只小猪的体重" << endl;
cin >> num2;
cout << "请输入第三只小猪的体重" << endl;
cout << "三只小猪的体重分别为" << num1 << num2 << num3 << endl;
cin >> num3;
if (num1 > num2)
{
if (num1 > num3)
{
cout << "小猪1是最重的" << endl;
}
else
{
cout << "小猪3是最重的" << endl;
}
}
else
{
if (num2> num3)
{
cout << "小猪2是最重的" << endl;
}
else
{
cout << "小猪3是最重的" << endl;
}
}
}
作用:通过三目运算符实现简单的判断 语法:表达式1 ? 表达式2 : 表达式3 解释 如果表达式1的值为真,执行表达式2,并返回表达式2的结果; 如果表达式1值为假,执行表达式3,并返回表达式3的结果 实例:
#include<iostream>
using namespace std;
int main() {
int a = 10;
int b = 20;
int c = 0;
c = a > b ? a : b;
cout << "c=" << c << endl;
//在c++中三目运算符返回的式变量,可以继续赋值
(a > b ? a : b) = 200;
cout << "a=" << a << endl;
cout << "b=" << b << endl;//注意a没有发生任何变化,b变成了200
}
作用:执行多条件分支语句 语法:
switch(表达式){
case 结果1:执行语句;break;
case 结果2:执行语句;break;
...
default:执行语句;break;
}
表达式,只能放一个整型或者字符型,不可以判断一个区间 优点是结构清晰,执行效率高
#include<iostream>
using namespace std;
int main() {
/*
switch语句
给电影打分
10-9经典
8-7非常好
6-5一般
5以下烂片
*/
//提示用户输入
cout << "请输入你的打分0-10" << endl;
//用户开始打分
int score = 0;
cin >> score;
cout << "你打的分为:" << score << endl;
switch (score)
{
case 10:
cout << "您认为式经典电影" << endl;
break;
case 9:
cout << "您认为是经典电影" << endl;
break;
case 8:
case 7:
cout << "您认为电影非常好" << endl;
break;
case 6:
case 5:
cout << "您认为电影一般" << endl;
break;
default:
cout << "您认为电影很烂" << endl;
break;
}
}
作用:满足循环条件,执行循环语句 语法:while(循环条件){循环语句} 解释:只要循环条件的结果为真,就执行循环语句
#include<iostream>
using namespace std;
int main() {
int num = 0;
while (num<10)
{
cout << "num=" << num << endl;
num++;
}
}
案例练习:猜数字(0-100)之间
#include<iostream>
using namespace std;
int main() {
//系统生成随机数
int num = rand() % 100 + 1;//rand()%生成0~99随机数
//玩家进行猜测
int guess = 0;
int count = 0;
while (true)
{
count++;
cout << "请输入你猜的数" << endl;
cin >> guess;
if (guess == num)
{
cout << "恭喜你,你猜对了,一共猜了" << count <<"次" << endl;
break;
}
else
{
if (guess>num)
{
cout << "你猜的太大了" << endl;
}
else
{
cout << "你猜的太小了" << endl;
}
}
}
//判断玩家的猜测
//猜对,退出游戏
//猜错,提示过大过小,返回第二步
}
作用:满足循环条件,执行循环语句 语法:do{循环语句}while(循环条件); 注意:与while的区别在于do...while会先执行一次循环语句,在判断循环条件
#include<iostream>
using namespace std;
int main() {
//do while 输出0-9
int num = 0;
do
{
cout << "num=" << num << endl;
num++;
} while (num<10);
}
作用:满足循环条件,执行循环语句 语法:for(起始表达式;条件表达式;末尾循环体){循环语句;} 实例
int main(){
for(int i = 0;i < 10;i++){
cout << i << endl;
}
}
案例:敲桌子,从1到100,如果数字个位含有7,或者数字十位含有7,或者该数字是7的倍数,我们打印敲桌子,其余数字直接打印输出
#include<iostream>
using namespace std;
int main() {
for (int i = 1; i <= 100; i++) {
if ((i%10==7)||(i%7==0)||(i/10==7))
{
cout << "敲桌子" << endl;
}
else
{
cout << i << endl;
}
}
}
作用:循环之内再嵌套一层循环
#include<iostream>
using namespace std;
int main() {
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++)
{
cout << "* ";
}
cout << endl;
}
}
案例:乘法口诀表
#include<iostream>
using namespace std;
int main() {
for (int i = 0; i < 9; i++)
{
for (int j = 0; j <= i; j++)
{
cout << j + 1 << "×" << i + 1 << "=" << (j + 1) * (i + 1)<<"\t";
}
cout << endl;
}
}
#include<iostream>
using namespace std;
int main() {
cout << "1,sfs" << endl;
cout << "2,sfs" << endl;
goto FLAG;
cout << "3,sfs" << endl;
cout << "4,sfs" << endl;
cout << "5,sfs" << endl;
FLAG:
cout << "6,sfs" << endl;
}
所谓数组,就是一个集合,里面放了很多相同类型的数据元素 特点1:数组中每个数据元素都是相同的数据类型 特点2:数组是由连续内存位置组成的
定义方式:
#include<iostream>
using namespace std;
int main() {
/*定义方式:
* 数据类型 数组名[数组长度];
* 数据类型 数组名[数组长度] = {值1,值2,...}
* 数据类型 数组名[] = {值1,值2,...}
*/
// 1. 数据类型 数组名[数组长度]
int arr[5];
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
arr[3] = 40;
arr[4] = 50;
//访问数据元素
cout << arr[0] << endl;
//2.数据类型 数组名[数组长度] = {值1,值2,。。。}
int arr2[5] = { 10,20,30,40,50 };//如果在初始化的时候没有全部填写完,会用0填补剩余数据
for (int i = 0; i < 5; i++)
{
cout << arr[i] << endl;
}
// 3.数据类型 数组名[] = {值1,值2.。。};
int arr3[] = { 3,3,25,652,24,62 };
}
一维数组名的用途:
int arr3[] = { 3,3,25,652,24,62 };
//整个数组占用内存大小
cout << "arr3整个数组占用空间" << sizeof(arr3) << endl;
//这个数组有多少元素
cout << "arr3元素个数" << sizeof(arr3) / sizeof(arr3[0]) << endl;
//数组首地址
cout << "数组arr3首地址" << (int)arr << endl;
//数组中第一个元素的地址
cout << "数组中第一个元素地址为:" << (int)&arr[0] << endl;
//说明首地址和第一个元素地址相等
//第二个元素地址
cout << "数组中第二个元素地址为:" << (int)&arr[1] << endl;
//说明数组中每个元素紧挨着
//注意:数组名是常量,不可以进行赋值操作
案例:五只小猪称体重 在一个数组中记录了五只小猪的体重,如:int arr[5] = [300,350,200,400,250]找出并打印最重的小猪体重
#include<iostream>
using namespace std;
int main() {
//在一个数组中记录了五只小猪的体重,如:int arr[5] = [300,350,200,400,250]找出并打印最重的小猪体重
int arr[5] = { 300, 350, 200, 400, 250 };
int max = 0;
int num = 0;
for (int i = 0; i < size(arr); i++)
{
if (arr[i] > max)
{
max = arr[i];
num = i;
}
}
cout << "最重的小猪是" << num << "号" << "他的体重是" << max << endl;
}
案例:数组元素逆置 请申请一个5元素的数组,并且将元素逆置
#include<iostream>
using namespace std;
int main() {
int arr[5] = {300, 350, 200, 400, 250};
int start = 0;//起始元素下标
int temp = 0;
int end = sizeof(arr) / sizeof(arr[0]) - 1;//结束位置下标
cout << "原数组为" << endl;
for (int i = 0; i < size(arr); i++)
{
cout << arr[i] << " ";
}
cout << endl;
for (int i = 0; i < size(arr); i++)
{
if (start == end)
{
break;
}
temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
start++;
end--;
}
cout << "调整后的数组为" << endl;
for (int i = 0; i < size(arr); i++)
{
cout << arr[i] << " ";
}
}
作用:最常用的排序算法,对数组内元素进行排序
#include<iostream>
using namespace std;
int main() {
//利用冒泡排序实现升序排序
int arr[9] = { 4,2,8,0,5,7,1,3,9 };
int temp = 0;
cout << "排序前" << endl;
for (int i = 0; i < size(arr); i++)
{
cout << arr[i] << " ";
}
cout << endl;
for (int i = 0; i < size(arr)-1; i++)
{
for (int j = 0; j < size(arr)-i-1; j++)
{
if (arr[j]>arr[j+1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
cout << "排序后" << endl;
for (int i = 0; i < size(arr); i++)
{
cout << arr[i] << " ";
}
}
二维数组就是在一维数组上多加一个维度 二维数组定义的四种方式
#include<iostream>
using namespace std;
int main() {
/*
二维数组定义的四种方式
1. 数据类型 数组名[行数][列数];
2. 数据类型 数组名[行数][列数] = {{数据1,数据2},{数据1,数据2}};
3. 数据类型 数组名[行数][列数] = {数据1,数据2,数据3,数据4};
4. 数据类型 数组名[][列数] = {数据1,数据2,数据3,数据4};
*/
int arr[2][3];
int arr1[2][3] = { {3,3,3},{3,2,4} };
int arr2[][3] = { {3,3,3},{3,2,4} };
int arr3[2][3] = { 3,3,3,4,4,4 };
}
二维数组的别名
#include<iostream>
using namespace std;
int main() {
/*
* 查看二维数组所占内存空间
* 获取二维数组首地址
*/
int arr[2][3] =
{
{1,2,3},
{4,5,6}
};
cout << "二维数组占用空间为" << sizeof(arr) << endl;
cout << "二维数组第一行占用空间" << sizeof(arr[0]) << endl;
cout << "二维数组第一个元素占用内存" << sizeof(arr[0][0]) << endl;;
cout << "二维数组行数" << size(arr) << endl;
cout << "二维数组列数" << size(arr[0]) << endl;
//查看二维数组的首地址
cout << "二维数组首地址" << (int)arr << endl;
cout << "二维数组第一行首地址" << (int)arr[0] << endl;
cout << "二维数组第一个元素首地址" << (int)&arr[0][0] << endl;
}
二维数组应用案例 考试成绩统计,分别输出三名同学总成绩
#include<iostream>
#include<string>
using namespace std;
int main() {
int score[3][3] =
{
{100,100,100},
{90,50,100},
{60,70,80}
};
string name[3] = { "张三","李四","王五" };
cout << "二维数组为:" << endl;
for (int i = 0; i < size(score); i++)
{
int sum = 0;//统计分数综合
for (int j = 0; j < size(score[0]); j++)
{
sum += score[i][j];
cout << score[i][j] << "\t";
}
cout <<name[i]<<"的" << "个人的总分为" << sum << endl;
}
}
作用:讲一段经常使用的代码封装起来,减少重复代码 一个较大的程序,一般分为若干个程序块,每个模块实现特定功能
函数的定义一般包括:
int add(int num1, int num2) {
int sum = num1 + num2;
return sum;
}
#include<iostream>
using namespace std;
//num1,num2叫做形参
int add(int num1, int num2) {
int sum = num1 + num2;
return sum;
}
int main() {
//函数调用
//调用整型的加法函数
int a = 10;
int b = 20;
//a,b叫做实参
//调用函数时,实参传递给形参
int c = add(a, b);
cout << "c=" << c << endl;
}
常见的函数样式有4种
#include<iostream>
using namespace std;
/*
常见的函数样式有4种
1. 无参无返
2. 有参无返
3. 无参有返
4. 有参有返
*/
//无参无返
void test01() {
cout << "this is test01" << endl;
}
//有参无返
void test02(int a) {
cout << "this is test02\t" << a << endl;
}
//无参有返
int test03() {
cout << "this is test03" << endl;
return 1000;
}
//有参有返
int test04(int a) {
cout << "this is test04 a=" << a << endl;
return a;
}
int main() {
test01();
test02(3);
int num1 = test03();
cout << "num1=" << num1 << endl;
int num2 = test04(2);
cout << "num2=" << num2 << endl;
}
作用:告诉编译器名称及如何调用函数,函数的主体可以单独定义 函数的声明可以多次,但是函数的定义只可以有一次 函数声明举例:int max(int a,int b);函数声明的好处就是可以把自定义的函数写在main函数之后,相当于提前告诉编译器函数的存在
作用:让代码结构更加清晰 函数分文件编写一般有4个步骤
#include<iostream>
#include "swap.h"
using namespace std;
//函数分文件编写,实现两个数字进行交换的函数
//void swap(int a, int b)
//{
// int temp = a;
// a = b;
// b = temp;
// cout << "a=" << a << endl;
// cout << "b=" << b << endl;
//}
int main() {
int a = 10;
int b = 20;
swap(a, b);
}
头文件
#pragma once
#include<iostream>
using namespace std;
void swap(int a, int b);
源文件
#include "swap.h"
void swap(int a, int b)
{
int temp = a;
a = b;
b = temp;
cout << "a=" << a << endl;
cout << "b=" << b << endl;
}
指针的作用:可以通过指针间接访问内存
指针变量定义语法:数据类型 * 变量名: 实例:
#include<iostream>
using namespace std;
int main() {
//定义指针
int a = 10;
//指针定义的语法:数据类型 * 指针变量名
int* p;//定义int类型的指针变量
//现在让p保存a的地址
p = &a;//指针记录的就是地址
cout << "a的地址为" << &a << endl;
cout << "p的值为" << p << endl;
//使用指针
//可以通过解引用的方式来找到指针指向的内存
//指针前加*代表解引用,找到指针指向的内存中
*p = 1000;
cout << "a=" << a << endl;
cout << "p=" << p << endl;
}
输出:
a的地址为000000D6A315FBF4
p的值为000000D6A315FBF4
a=1000
p=000000D6A315FBF4
提问:指针也是一种数据类型,那么这种数据类型所占空间是多少? 在32位操作系统下,指针占用4个字节,64位下占用8个字节 实例:
#include<iostream>
using namespace std;
int main() {
//指针所占空间
//在32位操作系统下,指针是占用4个字节空间大小,不管是什么数据类型
int a = 10;
int* p = &a;
cout << "sizeof int * =" << sizeof(int*) << endl;
cout << "sizeof int * =" << sizeof(float*) << endl;
cout << "sizeof int * =" << sizeof(char*) << endl;
cout << "sizeof int * =" << sizeof(double*) << endl;
}
#include<iostream>
using namespace std;
int main() {
//空指针,空指针用于对指针变量初始化
int* p = NULL;
//空指针是不可以访问的
//0-255内存编号是系统占用内存,不可以用户访问
*p = 100;
}
#include<iostream>
using namespace std;
int main() {
//野指针
//在程序中,尽量避免野指针
int* p = (int*)0x1100;//没有申请的内存空间
cout << *p << endl;
}
const修饰指针有三种情况
简单记忆:
#include<iostream>
using namespace std;
int main() {
//const修饰指针 常量指针
int a = 10;
int b = 20;
//int* p = &a;
const int* p = &a;
//*p = 20;错误写法,因为常量指针是指向常量的指针,指向的值不可以修改
p = &b;
cout << "p=" << p << endl;
//const修饰常量 指针常量
int* const p2 = &a;
//p2 = &b;错误,因为指针常量指针不可以改变指向
*p2 = 1000;
cout << "a=" << a << endl;
//const既修饰指针又修饰常量
const int* const p3 = &a;
//p3 = &b;错误,指向不可改
//*p3 = 1000;错误,指向的值也不可以改
}
作用:利用指针访问数组中元素 实例:
#include<iostream>
using namespace std;
int main() {
//指针和数组
//利用指针访问数组中的元素
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
cout << "第一个元素:" << arr[0] << endl;
int* p = arr;//arr就是数组首地址
cout << p << endl;
cout << "利用指针访问第一个元素" << *p << endl;
p++;
cout << "利用指针访问第二个元素" << *p << endl;
//利用指针遍历这个数组
int* p2 = arr;
for (int i = 0; i < size(arr); i++)
{
cout << "数组第" << i+1 << "个元素:" << *p2 << endl;
p2++;
}
}
作用:利用指针做函数参数,可以修改实参的值
//实现两个数字进行交换
#include<iostream>
using namespace std;
void swap01(int a, int b) {
int temp = a;
a = b;
b = temp;
cout << "swap01a=" << a << endl;
cout << "swap02b=" << b << endl;
}
void swap02(int* p,int* p2){
int temp = *p;
*p = *p2;
*p2 = temp;
}
int main() {
int a = 10;
int b = 20;
//值传递,形参影响不了实参
//swap01(a, b);
//地址传递,地址传递,可以修饰实参
swap02(&a, &b);
cout << "a=" << a << endl;
cout << "b=" << b << endl;
}
案例描述:封装一个函数,利用冒泡排序,实现对整型数组的升序排列 例如数组:int arr[10] = {4,3,6,9,1,2,10,8,7,5};
#include<iostream>
using namespace std;
//打印数组
void printArray(int* arr,int len) {//这边也可以写成int arr[]
for (int i = 0; i < len; i++)
{
cout << arr[i] << "\t";
}
}
//冒泡排序
void bubbleSort(int* arr, int len){
for (int i = 0; i < len-1; i++)
{
for (int j = 0; j < len-i-1; j++)
{
if (arr[j]>arr[j+1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
int main() {
//先创建数组
int arr[10] = {4,3,6,9,1,2,10,8,7,5};
//创建函数,实现冒泡排序
bubbleSort(arr, size(arr));
//打印排序后的数组
printArray(arr, size(arr));
}
结构体属于用户自定义的数据类型,允许用户存储不同的数据类型
通过结构体创建变量的方式有三种:
#include<iostream>
#include<string>
using namespace std;
//创建学生数据类型:学生包括(姓名,年龄,分数)
struct Student
{
//成员列表
//姓名
string name;
//年龄
int age;
//分数
int score;
}s3;//顺便创建一个结构体变量s3
//通过学生类型创建具体学生
//struct Student s1
//struct Student s2 = {...}
//在定义结构体时顺便创建结构体变量
int main() {
struct Student s1;//结构体创建时struct关键字可以省略,但是定义的时候不可以省略
//给s1属性赋值,通过.访问结构体变量中的属性
s1.name = "张三";
s1.age = 18;
s1.score = 100;
cout << "姓名:" << s1.name << " 年龄:" << s1.age << " 分数:" << s1.score << endl;
//struct Student s2 = {...}
struct Student s2 = { "李四",28,13 };
cout << "姓名:" << s2.name << " 年龄:" << s2.age << " 分数:" << s2.score << endl;
//定义结构体时顺便创建结构体变量
s3.name = "王五";
s3.age = 20;
s3.score = 50;
cout << "姓名:" << s3.name << " 年龄:" << s3.age << " 分数:" << s3.score << endl;
}
作用:将自定义的结构体放入到数组中方便维护 语法:struct 结构体名 数组名[元素个数] = {{},{},...{}} 实例:
#include<iostream>
#include<string>
using namespace std;
struct Student
{
string name;
int age;
int score;
};
int main() {
//创建结构体数组
Student stuArray[3] =
{
{"张三",28,100},
{"李四",28,99},
{"王五",43,33}
};
//给结构体数组中元素赋值,改写一个
stuArray[2].name = "赵六";
stuArray[2].age = 85;
stuArray[2].score = 60;
//遍历结构体数组
for (int i = 0; i < 3; i++)
{
cout << "姓名:" << stuArray[i].name
<< " 年龄:" << stuArray[i].age
<< " 分数:" << stuArray[i].score<<endl;
}
}
作用:通过指针访问结构体中的成员
#include<iostream>
#include<string>
using namespace std;
//结构体指针
struct student
{
string name;
int age;
int score;
};
int main() {
//创建学生的结构体变量
student s = { "张三",18,100 };
//通过指针指向结构体变量
student* p = &s;
//通过指针访问结构体变量中的数据'->'
cout << "姓名" << p->name << " 年龄" << p->age << " 分数" << p->score << endl;
}
作用:结构体的成员可以是另一个结构体 例如:每个老师辅导一个学员,一个老师的结构体中,记录一个学生的结构体 实例:
#include<iostream>
#include<string>
using namespace std;
//定义学生结构体
struct student
{
string name;
int age;
int score;
};
//定义老师结构体
struct teacher
{
int id;//教师编号
string name;//教师姓名
int age;//年龄
struct student stu;
};
int main() {
//结构体嵌套结构体
//创建老师
teacher t;
t.id = 10000;
t.name = "老王";
t.age = 50;
t.stu.age = 28;
t.stu.name = "小王";
t.stu.score = 48;
cout << "老师姓名:" << t.name << " 老师编号" << t.id << " 老师年龄:" << t.age
<< " 老师辅导的学生:" << t.stu.name << endl;
}
作用:将结构体作为参数向函数中传递 传递方式有两种
#include<iostream>
#include<string>
using namespace std;
struct student
{
//姓名
string name;
int age;
int score;
};
//值传递
void printStudent01(student stu)
{
cout << "main函数中打印姓名:" << stu.name << " 年龄:" << stu.age << " 得分" << stu.score << endl;;
}
//地址传递
void printStudent02(student* stu)
{
cout << "main函数中打印姓名:" << stu->name << " 年龄:" << stu->age << " 得分" << stu->score << endl;;
}
int main()
{
//结构体做函数参数
//将学生传入到一个参数中,打印学生身上所有信息
//创建一个结构体变量
student stu;
stu.name = "张三";
stu.score = 48;
stu.age = 29;
//值传递
printStudent01(stu);
//地址传递
printStudent02(&stu);
//cout << "main函数中打印姓名:" << stu.name << " 年龄:" << stu.age << " 得分" << stu.score;
}
作用:用const来防止误操作 实例:
#include<iostream>
#include<string>
using namespace std;
//const的使用场景
struct student
{
string name;
int age;
int score;
};
//将函数中的形参改为指针,可以减少内存空间,而且不会复制新的副本出来
//为了防止误操作(不小心在函数内部把属性给改了)就需要const
void printStudent(const student* s) {//加入const之后,一旦有修改的操作就会报错,可以防止我们误操作。
//s->name = "3dfs";报错
cout << "main函数中打印姓名:" << s->name<< " 年龄:" << s->age << " 得分" << s->score;
}
int main() {
//创建结构体变量
student s = { "张三",15,89 };
//通过函数来打印结构体变量的信息
printStudent(&s);
system("pause");
return 0;
}
#include<iostream>
#include<string>
#include<ctime>
using namespace std;
struct student
{
string sName;
int score;
};
//老师的结构体
struct teacher
{
string tName;
student sArray[5];
};
//给老师和学生赋值的函数
void allocateSpace(teacher tArray[], int len)//这里也可以写成teacher *tArray
{
string nameSeed = "ABCDE";
for (int i = 0; i < len; i++)
{
tArray[i].tName = "teacher_";
tArray[i].tName += nameSeed[i];
//通过循环给每名老师所带的学生赋值
for (int j = 0; j < 5; j++)
{
tArray[i].sArray[j].sName = "student_";
tArray[i].sArray[j].sName += nameSeed[j];
int random = rand() % 61 + 40;//40-100
tArray[i].sArray[j].score = random;
}
}
}
//打印信息的函数
void printInfo(teacher tArray[], int len) {
for (int i = 0; i < len; i++)
{
cout << "老师的姓名:\t" << tArray[i].tName << endl;
for (int j = 0; j < 5; j++)
{
cout << "学生姓名:\t" << tArray[i].sArray[j].sName <<
"\t考试分数:\t" << tArray[i].sArray[j].score << endl;
}
}
}
int main() {
//随机数种子
srand((unsigned int)time(NULL));
//创建3名老师的数组
teacher tArray[3];
//函数给3名老师赋值,并给老师所带的学生信息赋值
allocateSpace(tArray, size(tArray));
//打印所有老师以及所带的学生信息
printInfo(tArray, size(tArray));
}
案例描述: 设计一个英雄的结构体:包括成员姓名,年龄,性别,创建结构体数组,数组中存放5名英雄 通过冒泡排序算法,将数组中的英雄按照年龄进行升序排序,最终打印排序后的结果
#include<iostream>
#include<string>
using namespace std;
struct hero
{
string name;
int age;
string sex;
};
//起始状态打印
void printInfoBegin(hero* heroArray,int len)
{
for (int i = 0; i < len; i++)
{
cout << "成员姓名:\t" << heroArray[i].name << "\t年龄:\t" << heroArray[i].age
<< "\t性别:" << heroArray[i].sex << endl;
}
}
//按照年龄升序排列
void printInfoBubbleSort(hero* heroArray, int len)
{
for (int i = 0; i < len-1; i++)
{
for (int j = 0; j < len-1-i; j++)
{
if (heroArray[j].age > heroArray[j+1].age)
{
hero temp = heroArray[j];
heroArray[j] = heroArray[j + 1];
heroArray[j + 1] = temp;
}
}
}
}
int main() {
//创建结构体数组
hero heroArray[5] =
{
{"刘备",23,"男"},
{"关羽",22,"男"},
{"张飞",20,"男"},
{"赵云",21,"男"},
{"貂蝉",19,"女"}
};
//打印一下看看原始排列
printInfoBegin(heroArray, size(heroArray));
//排序后
cout << "------------------------------------------------------" << endl;
printInfoBubbleSort(heroArray, size(heroArray));
printInfoBegin(heroArray, size(heroArray));
}
通讯录是一个可以记录亲人好友信息的工具 本教程主要利用C++来实现一个通讯录管理系统 系统中需要实现的功能如下:
#include<iostream>
#include<string>
using namespace std;
//封装函数显示该界面,如void showMenu()
//在main函数中调用封装好的函数
//1. 显示菜单
void showMenu()
{
cout << "*************************" << endl;
cout << "***** 1、添加联系人 *****" << endl;
cout << "***** 2、显示联系人 *****" << endl;
cout << "***** 3、删除联系人 *****" << endl;
cout << "***** 4、查找联系人 *****" << endl;
cout << "***** 5、修改联系人 *****" << endl;
cout << "***** 6、清空联系人 *****" << endl;
cout << "***** 7、退出通讯录 *****" << endl;
cout << "*************************" << endl;
}
int main()
{
//菜单调用
showMenu();
}
功能描述:退出通讯录系统 思路:根据用户不同的选择,进入不同的功能,可以选择switch分支结构,将整个架构进行搭建 当用户选择0时,执行退出,选择其他先不做操作,也不会退出程序。
功能描述: 实现添加联系人功能,联系人上限为1000人,联系人信息包括(姓名、性别、年龄、联系电话、家庭住址) 添加联系人实现步骤:
功能描述:显示通讯录中已有的联系人信息 显示联系人实现步骤:
功能描述:按照姓名进行删除联系人 删除联系人实现步骤:
功能描述:按照姓名查看指定联系人信息 查找联系人实现步骤
功能描述:按照姓名重新修改指定联系人 修改联系人实现步骤:
功能描述:清空通讯录中所有信息 清空联系人实现步骤
#include<iostream>
#include<string>
#define MAX 1000//最大数
using namespace std;
//封装函数显示该界面,如void showMenu()
//在main函数中调用封装好的函数
//1. 显示菜单
void showMenu()
{
cout << "*************************" << endl;
cout << "***** 1、添加联系人 *****" << endl;
cout << "***** 2、显示联系人 *****" << endl;
cout << "***** 3、删除联系人 *****" << endl;
cout << "***** 4、查找联系人 *****" << endl;
cout << "***** 5、修改联系人 *****" << endl;
cout << "***** 6、清空联系人 *****" << endl;
cout << "***** 7、退出通讯录 *****" << endl;
cout << "*************************" << endl;
}
//设计联系人结构体
struct Person
{
string mName;
int mGender;//性别,1男,2女
int mAge;
string mPhone;
string mAddr;
};
//通讯录结构体
struct Addressbooks
{
Person personArray[MAX];//通讯录中保存的联系人数组
int mSize;//当前记录的联系人个数
};
//1.添加联系人
void addPerson(Addressbooks* abs)
{
//判断通讯录是否已经满了,如果满了就不再添加
if (abs->mSize == MAX)
{
cout << "通讯录已经满了,无法添加" << endl;
return;
}
else
{
//添加具体联系人
//姓名
string name;
cout << "输入联系人姓名:" << endl;
cin >> name;
abs->personArray[abs->mSize].mName = name;
//性别
cout << "请输入性别,1代表男,2代表女" << endl;
int sex = 0;
while (true)
{
//如果输入的是1或者2,可以退出循环,因为输入的是正确值,否则重新输入
cin >> sex;
if (sex == 1 || sex == 2)
{
abs->personArray[abs->mSize].mGender = sex;
break;
}
cout << "输入有误,请重新输入" << endl;
}
//年龄
cout << "请输入年龄:" << endl;
int age = 0;
while (true)
{
//如果输入的年龄在1-200之间,可以退出循环,否则重新输入
cin >> age;
if (age>=1&&age<=200)
{
abs->personArray[abs->mSize].mAge = age;
break;
}
cout << "输入有误,请重新输入" << endl;
}
//电话
cout << "请输入联系电话:" << endl;
string phone;
cin >> phone;
abs->personArray[abs->mSize].mPhone = phone;
//家庭住址
cout << "请输入家庭住址:" << endl;
string address;
cin >> address;
abs->personArray[abs->mSize].mAddr = address;
//更新通讯录人数
abs->mSize++;
cout << "添加成功!" << endl;
system("pause");//请按任意键继续
system("cls");//清屏
}
}
//2.显示联系人
void showPerson(Addressbooks* abs)
{
//判断通讯录中人数是否为0,如果为0,提示记录为空
if (abs->mSize == 0)
{
cout << "记录为空" << endl;
}
else
{
for (int i = 0; i < abs->mSize; i++)
{
cout << "姓名:" << abs->personArray[i].mName << "\t"
<< "性别:" << (abs->personArray[i].mGender == 1?"男" :"女") << "\t"
<< "年龄:" << abs->personArray[i].mAge << "\t"
<< "电话:" << abs->personArray[i].mPhone << "\t"
<< "住址:" << abs->personArray[i].mAddr << endl;
}
}
system("pause");
system("cls");
}
//
//检测联系人是否存在,如果存在,返回具体位置,否则返回-1
int isExist(Addressbooks* abs, string name)
{
for (int i = 0; i < abs->mSize; i++)
{
if (abs->personArray[i].mName == name)
{
return i;
}
}
return -1;//如果遍历结束都没有找到返回-1.
}
//3.删除联系人函数
void deletePerson(Addressbooks* abs)
{
cout << "请输入一下您要删除的联系人" << endl;
string name;
cin >> name;
int ret = isExist(abs, name);
if (ret==-1)
{
//未查到
cout << "查无此人" << endl;
}
else
{
//查到了此人
//将要删除的元素的后面元素向前移动,并且让通讯录中记录的人员个数做一个-1的操作
for (int i = ret;i<abs->mSize;i++)
{
//数据迁移
abs->personArray[i] = abs->personArray[i + 1];
}
abs->mSize--;//更新一下通讯录中的人员数。
cout << "删除成功" << endl;
}
system("pause");
system("cls");
}
//4.查找指定联系人信息
void findPerson(Addressbooks* abs)
{
cout << "请输入您要查找的联系人" << endl;
string name;
cin >> name;
//判断指定联系人是否存在通讯录中
int res = isExist(abs, name);
if (res!= -1)//找到了
{
cout << "姓名:" << abs->personArray[res].mName << "\t";
cout << "性别:" << abs->personArray[res].mGender << "\t";
cout << "年龄:" << abs->personArray[res].mAge << "\t";
cout << "电话:" << abs->personArray[res].mPhone << "\t";
cout << "住址:" << abs->personArray[res].mAddr << "\t";
}
else
{
cout << "未找到联系人" << endl;
}
system("pause");
system("cls");
}
//5.修改指定联系人
void modifyPerson(Addressbooks* abs)
{
//想修改哪一个的信息
cout << "请输入你想修改的联系人的姓名:" << endl;
string name;
cin >> name;
int res = isExist(abs,name);
if (res != -1)
{
cout << "原始信息为:" << endl;
cout << "姓名:" << abs->personArray[res].mName << "\t";
cout << "性别:" << abs->personArray[res].mGender << "\t";
cout << "年龄:" << abs->personArray[res].mAge << "\t";
cout << "电话:" << abs->personArray[res].mPhone << "\t";
cout << "住址:" << abs->personArray[res].mAddr << "\t" << endl;;
cout << "------------------------------" << endl;
//姓名
string name;
cout << "请输入姓名" << endl;
cin >> name;
abs->personArray[res].mName = name;
//性别
cout << "请输入性别" << endl;
cout << "1---男" << endl;
cout << "2---女" << endl;
int sex = 0;
while (true)
{
cin >> sex;
if (sex == 1 || sex == 2)
{
//输入正确,则退出循环
abs->personArray[res].mGender = sex;
break;
}
cout << "输入有误,请重新输入" << endl;
}
//年龄
cout << "请输入年龄:" << endl;
int age = 0;
cin >> age;
abs->personArray[res].mAge = age;
//电话
cout << "请输入联系电话" << endl;
string phone;
cin >> phone;
abs->personArray[res].mPhone = phone;
//家庭住址
cout << "请输入家庭住址" << endl;
string address;
cin >> address;
abs->personArray[res].mAddr = address;
cout << "修改成功" << endl;
}
else//未找到联系人
{
cout << "查无此人" << endl;
}
system("pause");
system("cls");
}
//6.清空联系人
void cleanPerson(Addressbooks* abs)
{
abs->mSize = 0;//将当前记录联系人数量置为0,做逻辑清空
cout << "通讯录已经清空" << endl;
system("pause");
system("cls");
}
int main()
{
//创建通讯录结构体变量
Addressbooks abs;
//初始化通讯录中当前人员个数
abs.mSize = 0;
int select = 0;
while (true)
{
//菜单调用
showMenu();
cin >> select;
switch (select)
{
case 1://添加联系人
addPerson(&abs);
break;
case 2://显示联系人
showPerson(&abs);
break;
case 3://删除联系人
deletePerson(&abs);
break;
case 4://查找联系人
findPerson(&abs);
break;
case 5://修改联系人
modifyPerson(&abs);
break;
case 6://清空联系人
cleanPerson(&abs);
break;
case 0://退出通讯录
cout << "欢迎下次使用" << endl;
system("pause");
return 0;
break;
default:
break;
}
}
}
C++程序在执行时,将内存大方向划分为4个区域
int* func()
{
//利用new关键字,可以将数据开辟到堆区
int* p = new int(10);//数据初始值10,返回的时一个地址编号。
//指针p本质也是一个局部变量,放在栈上,但是指针指向的数据是放在堆区。也就是说堆区的地址编号用栈区的指针保存了
return p;
}
int main()
{
//在堆区开辟数据
int* p = func();
cout<<*p <<endl;
}
#include<iostream>
using namespace std;
//new的基本用法
int* func()
{
//在堆区创建整型数据
//new返回是该数据类型的指针
int* p = new int(10);
return p;
}
void test01()
{
int* p = func();
cout << *p << endl;
cout << *p << endl;
cout << *p << endl;
//堆区数据由程序员管理开辟,程序员管理释放
//如果想释放堆区的数组,利用关键字delete
delete p;
//cout << *p << endl;//访问权限冲突,非法操作
}
//在堆区利用new开辟数组
void test02()
{
//创建10整型数据的数组
int* arr = new int[10];
for (int i = 0; i < 10; i++)
{
arr[i] = i + 100;//给10个元素赋值100-109
}
for (int i = 0; i < 10; i++)
{
cout << arr[i] << endl;
}
//释放堆区数组
//释放数组的时候,要加[]才可以
delete[] arr;
}
int main()
{
//test01();
test02();
}
作用:给变量起别名 语法:数据类型 &别名 = 原名 实例:
int a = 10;
//创建引用
int &b = a;//别名可以和原名一样
b = 100;
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
作用:函数传参时,可以利用引用的技术让形参修饰实参 优点:可以简化指针修改实参 实例:
#include<iostream>
using namespace std;
//交换函数
//值传递
void mySwap01(int a, int b)
{
int temp = a;
a = b;
b = temp;
}
//地址传递
void mySwap02(int* a, int* b)
{
int* temp = a;
a = b;
b = temp;
cout << "a=" << *a << endl;
cout << "b=" << *b << endl;
}
//引用传递
void mySwap03(int& a, int& b)
{
int temp = a;
a = b;
b = temp;
}
int main()
{
int a = 10;
int b = 20;
//mySwap01(a,b);
//mySwap02(&a, &b);
mySwap03(a, b);//引用传递,形参会修饰实参
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
作用:引用时可以作为函数的返回值存在的 注意:不要返回局部变量引用
#include<iostream>
using namespace std;
int& test01()
{
int a = 10;//局部变量保存在栈区
return a;
}
int main()
{
int& ref = test01();
cout << "ref=" << ref << endl;//第一次结果正确,是因为编译器做了保留
cout << "ref=" << ref << endl;//第二次结果错误,因为a的内存已经释放
}
用法:函数调用作为左值
#include<iostream>
using namespace std;
int& test01()
{
int a = 10;//局部变量保存在栈区
return a;
}
//函数的调用可以作为左值
int& test02()
{
static int a = 10;//静态变量存在全局区,全局区数据在程序结束后系统释放
return a;
}
int main()
{
int& ref = test02();
cout << "ref=" << ref << endl;//输出正确
cout << "ref=" << ref << endl;//输出正确
test02() = 1000;//函数调用可以作为左值,因为test02()返回的是a的一个引用,将引用赋值为1000
cout << "ref=" << ref << endl;//输出正确
cout << "ref=" << ref << endl;//输出正确
}
实例:
本质:引用的本质在c++内部实现是一个指针常量
//发现是引用,转换成int* const ref = &a;
void func(int& ref)
{
ref = 100;//ref是引用,转换成*ref = 100
}
int main(){
int a = 10;
//自动转换成int* const ref = &a;指针常量是只想不可改,也说明为什么引用不可更改
int& ref = a;
ref = 20;//内部发现ref是引用,自动帮我们转换成*ref = 20;
cout<<"a:"<<a<<endl;
cout<<"ref:"<<ref<<endl;
func(a);
return 0;
}
作用:常量引用主要是来修饰形参,防止误操作 在函数形参列表钟,可以加const修饰形参,防止形参改变实参
#include<iostream>
using namespace std;
//打印数据函数
void showValue(const int& val)
{
//val = 1000;
cout << "val=" << val << endl;
}
int main()
{
//常量引用
//使用场景:用来修饰形参,防止误操作
//int a = 10;
//int& ref = 10;//引用必须引一快合法的内存空间,这里是错误的
//const int& ref = 10;//加const之后,这又是对的,编译器将代码修改为
//ref = 20//加入const之后变为只读,不可以修改
//int temp = 10;
//int& ref = temp;
int a = 100;
showValue(a);
system("pause");
}
在c++钟,函数的形参里表中的形参可以有默认值
语法:返回值类型 函数名(参数=默认值){}
如果某个位置已经有了默认参数,那么从这个位置往后,从左到右都必须有默认值
声明和实现只能有一个有默认参数,另一个没有。如果是声明有默认参数,实现就没有,否则实现有默认参数,声明就没有。
#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;
}
c++钟函数的形参列表可以有占位参数,用来做占位,调用函数时必须填补该位置。 语法:返回值类型 函数名(数据类型){} 在现阶段的占位参数存在意义不大,但是后面的课程中会使用这个技术
#include<iostream>
using namespace std;
//占位参数
void func(int a,int)
{
cout << "this is func" << endl;
}
int main() {
func(10,10);
}
//占位参数也可以有默认参数void func(int a, int = 10)
#include<iostream>
using namespace std;
//函数重载
//可以让函数名相同,提高复用性
//函数重载的满足条件
/*
* 同一个作用域下
* 函数名相同
* 函数参数类型不同或者个数不同或者顺序不同
* 注意:函数的返回值不可以做为函数重载的条件
*/
void func()
{
cout << "func的调用" << endl;
}
void func(int a)
{
cout << "func的调用!!!!" << endl;
}
void func(double a)
{
cout << "double(func)的调用!!!!" << endl;
}
void func(int a,double b)
{
cout << "int a,double b" << endl;
}
void func( double b, int a)
{
cout << "double b, int a" << endl;
}
//注意函数的返回值不可以作为函数重载的条件
int func(int a, double b)
{
cout << "int a,double b" << endl;
}
void func(int a, double b)
{
cout << "int a,double b" << endl;
}
int main() {
//func();
//func(10.);
func(10.,10);
func(10, 10.);
}
#include<iostream>
using namespace std;
//函数重载的注意事项
//引用作为重载的条件
void func(int& a)//int &a = 10;不合法,引用必须引合法的内存空间
{
cout << "func的调用" << endl;
}
//函数重载碰到默认参数
void func(const int& a)//const int &a = 10;
{
cout << "func(const int &a)调用" << endl;
}
int main() {
int a = 10;
func(a);//如果是传入a会调入func(int& a)
func(10);//如果传入10会调入func(const int& a)
}
//函数重载碰到默认参数
#include<iostream>
using namespace std;
void func2(int a,int b=10)
{
cout << "func2(int a,int b)的调用" << endl;
}
void func2(int a)
{
cout << "func2(int a)的调用" << endl;
}
int main()
{
func2(10);//当函数重载碰到默认参数,出现二义性,因此尽量避免这种情况
}
c面向对象三大特性:封装、继承、多态 c认为万事万物皆为对象,对象上有其属性和行为
#include<iostream>
using namespace std;
//设计一个圆类,求圆的周长
const double PI = 3.14;
//class代表设计一个类,类后面紧跟着就是类名称
class Circle
{
//访问权限
//公共权限
public:
//属性
//半径
int m_r;
//行为
//获取圆的周长
double calculateZC()
{
return 2 * PI * m_r;
}
};
int main() {
//通过圆类,创建具体的圆对象(实例化)
Circle c1;
//给圆对象属性进行赋值
c1.m_r = 10;
cout << "圆的周长为:" << c1.calculateZC() << endl;
}
#include<iostream>
using namespace std;
//设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓名和学号
class Student
{
public:
string m_name;//姓名
int m_id;
void setName(string name) {
m_name = name;
}
void setId(int id) {
m_id = id;
}
void showStudent()
{
cout << "姓名:" << m_name << "学号:" << m_id << endl;
}
};
int main() {
//创建一个具体学生
Student s1;
//s1.m_name = "张三";
s1.setName("张三");
//s1.m_id = 1;
s1.setId(1);
s1.showStudent();
Student s2;
//s2.m_name = "李四";
s2.setName("李四");
//s2.m_id = 2;
s2.setId(2);
s2.showStudent();
}
#include<iostream>
using namespace std;
//访问权限
//三种
/*
1. public 公共权限 成员类内可以访问,类外可以访问
2. protected 保护权限 成员类内可以访问,类外不可以访问 儿子也可以访问父亲的保护内容。
3. 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 p1;
p1.m_Name = "李四";
p1.m_Car = "奔驰";//保护权限内容,在类外访问不到
p1.m_Password = 111111;//私有权限,在类外访问不到
}
#include<iostream>
using namespace std;
class C1
{
int m_A;//默认权限为私有private
};
struct C2
{
int m_A;//默认权限为公共public
};
int main()
{
C1 c1;
//c1.m_A = 100;//报错,class默认为私有权限
C2 c2;
c2.m_A = 100;//正确,struct默认权限为共有
}
#include<iostream>
#include<string>
using namespace std;
//成员属性设置为私有
//设计人类
class Person
{
public:
//写姓名
void setName(string name)
{
m_Name = name;
}
//获取姓名
string getName()
{
return m_Name;
}
//获取年龄 可读可写,如果想修改(年龄的范围是0~150之间)
int getAge()
{
m_Age = 0;//初始化为0
return m_Age;
}
//设置年龄
void setAge(int age)
{
if (age<0 || age>150)
{
m_Age = 0;
cout << "您输入的年龄有误,请确保年龄在0-150之间";
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;
cout << "年龄为:" << p.getAge() << endl;
p.setLover("苍井空");
p.setAge(120);
cout << "年龄为:" << p.getAge() << endl;
}
#include<iostream>
using namespace std;
//创建一个立方体的类
class Cube
{
//行为
public:
//设置长
void setL(double l)
{
m_L = l;
}
//获取长
double getL()
{
return m_L;
}
//设置宽
void setW(double w)
{
m_W = w;
}
//获取宽
double getW()
{
return m_W;
}
//设置高
void setH(double h)
{
m_H = h;
}
//获取高
double getH()
{
return m_H;
}
//获取立方体面积
double area()
{
return 2 * (m_H * m_L + m_H * m_W + m_L * m_W);
}
double getArea();
//获取立方体体积
double calculateV()
{
return m_L * m_H * m_W;
}
//利用成员函数来判断两个立方体是否相等
bool isSameByClass(Cube &c)
{
if (m_L == c.getL() && m_H == c.getH() && m_W == c.getW())
{
return true;
}
else
{
return false;
}
}
private:
//属性
double m_L;//长
double m_W;//宽
double m_H;//高
};
//利用全局函数判断两个立方体是否相等
bool isSame(Cube& c1, Cube& c2)
{
if (c1.getL() == c2.getL() && c1.getH() == c2.getH() && c1.getW() == c2.getW())
{
return true;
}
return false;
}
int main()
{
//创建立方体对象
Cube c1;
c1.setL(10.);
c1.setH(10.);
c1.setW(10);
cout << "c1的面积为:" << c1.area() << endl;
cout << "c2的体积为:" << c1.calculateV() << endl;
//创建第二个立方体
Cube c2;
c2.setH(10);
c2.setL(10);
c2.setW(10);
//判断两个立方体是否相等
bool ret = isSame(c1, c2);//利用全局函数判断
bool ret1 = c1.isSameByClass(c2);//利用成员函数判断
if (ret1)
{
cout << "c1和c2是相等的" << endl;
}
else
{
cout << "c1和c2是不想等的" << endl;
}
}
封装案例2:点和圆的关系 设计一个圆形类(Circle)和一个点类(Point),计算点和圆的关系。
#include<iostream>
using namespace std;
//根据点到圆心的距离和半径比较判断点在圆的情况。
//点类
class Point
{
public:
//设置x
void setX(double x)
{
m_X = x;
}
//获取x
double getX()
{
return m_X;
}
//设置y
void setY(double y)
{
m_Y = y;
}
//获取y
double getY()
{
return m_Y;
}
private:
int m_X;
int m_Y;
};
//圆类
class Circle
{
public:
//设置半径
void setR(double r)
{
m_R = r;
}
//获取半径
double getR()
{
return m_R;
}
//设置圆心
void setCenter(Point center)
{
m_Center = center;
}
//获取圆心
Point getCenter()
{
return m_Center;
}
private:
int m_R;//半径
Point m_Center;//圆心
};
//判断点和圆的关系
void isInCircle(Circle& c, Point& p)
{
//计算两点之间距离的平方
double distance = (c.getCenter().getX() - p.getX()) * (c.getCenter().getX() - p.getX()) +
(c.getCenter().getY() - p.getY()) * (c.getCenter().getY() - p.getY());
//计算半径的平方
int rDistance = c.getR() * c.getR();
//判断关系
if (distance == rDistance)
{
cout << "点在圆上" << endl;
}
else if (distance > rDistance)
{
cout << "点在圆外" << endl;
}
else
{
cout << "点在圆外" << endl;
}
}
int main()
{
//创建圆
Circle c1;
Point p1;
p1.setX(0);
p1.setY(0);
c1.setR(10);
c1.setCenter(p1);
Point p2;
p2.setX(10);
p2.setY(10);
isInCircle(c1, p2);
}
#include<iostream>
using namespace std;
class Person
{
public:
//构造函数的调用
/*
1. 构造函数,没有返回值,也不写void
2. 函数名称与类名称相同
3. 构造函数可以有参数,因此可以发生重载
4. 程序在调用对象时候会自动调用构造,无需手动调用,而且只会调用一次
*/
Person()
{
cout << "Person构造函数被调用" << endl;
}
//析构函数的调用
/*
1. 析构函数,没有返回值也不写void
2. 函数名称与类名称相同,在名称前加上符号~
3. 析构函数不可以有参数,因此不可以发生重载
4. 程序在对象销毁前自动调用析构,无需手动调用,而且只会调用一次。
*/
~Person()
{
cout << "Person的析构函数调用" << endl;
}
};
void test01()
{
Person p;//局部变量,开辟在栈上,test01执行完毕后,释放这个对象
}
int main()
{
//test01();
Person p;
system("pause");
}
#include<iostream>
using namespace std;
//构造函数的分类和调用
//分类
class Person
{
public:
//构造函数
Person()
{
cout << "Person的无参构造函数调用" << endl;
}
Person(int a)
{
age = a;
cout << "Person的有参构造函数调用" << endl;
}
//拷贝构造函数
Person(const Person &p)//不能把本体改了
{
cout << "Person的拷贝构造函数调用" << endl;
age = p.age;//将传入的人身上的所有属性,拷贝到我身上
}
~Person()
{
cout << "Person的析构函数调用" << endl;
}
int age;
};
//调用
void test01()
{
//括号法调用
Person p;//默认构造函数调用
Person p2(10);//调用有参构造
Person p3(p2);//调用拷贝构造函数
cout << "p2的年龄:" << p2.age << endl;
cout << "p3的年龄:" << p3.age << endl;
//注意事项
// 调用默认构造函数的时候,不要加(),不是Person p()
// Person p()编译器会认为是一个函数声明,不会认为是创建对象
//显示法
Person p1;
Person p2 = Person(10);//有参构造
Person p3 = Person(p2);//拷贝构造
Person(10);//匿名对象 特点:当前行执行结束后,系统会立即回收匿名对象
//注意事项2
//不要利用拷贝构造函数初始化匿名对象
Person(p3);//重定义 编译器会认为 Person (p3) == Person p3;
//隐式法调用
Person p4 = 10;//相当于写了Person p4 = Person(10);有参构造
Person p5 = p4;//相当于Person p5 = p4;拷贝构造
}
int main()
{
test01();
}
#include<iostream>
using namespace std;
//拷贝构造函数的调用时机
//使用一个已经创建完毕的对象来初始化一个新对象
//值传递的方式给函数参数来传值
//值方式返回局部对象
class Person
{
public:
Person()
{
cout << "Person默认构造函数被调用" << endl;
}
Person(int age)
{
cout << "Person的有参构造函数被调用" << endl;
m_Age = age;
}
Person(const Person &p)
{
m_Age = p.m_Age;
cout << "Person的拷贝构造函数被调用" << endl;
}
~Person()
{
cout << "Person的析构函数被调用" << endl;
}
int m_Age;
};
void test01()
{
Person p1(10);
Person p2(p1);
}
//值传递的方式给函数参数传值
void doWork(Person p)//拷贝
{
}
void test02()
{
Person p;
doWork(p);
}
int main()
{
//test01();
test02();
}
#include<iostream>
using namespace std;
/*
默认情况下,c++编译器至少给一个类添加3个函数
* 默认构造函数(无参,函数体为空)
* 默认析构函数(无参,函数体为空)
* 默认拷贝构造函数,对属性进行值拷贝
*/
class Person
{
public:
Person()
{
cout << "Person默认构造函数调用" << endl;
}
Person(int age)
{
m_Age = age;
cout << "Person的有参构造函数调用" << endl;
}
/*Person(const Person& p)
{
m_Age = p.m_Age;
cout << "Person的拷贝构造函数调用" << endl;
}*/
~Person()
{
cout << "Person的析构函数调用" << endl;
}
int m_Age;
};
void test01()
{
Person p;
p.m_Age = 18;
Person p2(p);//拷贝构造函数
cout << "p2的年龄为:" << p2.m_Age << endl;
}
int main()
{
test01();
}
#include<iostream>
using namespace std;
class Person
{
public:
Person()
{
cout << "Person的默认构造函数调用" << endl;
}
Person(int age, int height)
{
m_Height = new int(height);
m_Age = age;
cout << "Perosn的有参构造函数调用" << endl;
}
//自己实现的拷贝构造函数,解决浅拷贝带来的问题
Person(const Person& p)
{
cout << "自己实现的拷贝构造函数" << endl;
m_Age = p.m_Age;
//m_Height = p.m_Height;编译器默认实现的就是这行代码
//深拷贝操作
m_Height = new int(*p.m_Height);
}
~Person()
{
cout << "Person的析构函数被调用" << endl;
if (m_Height != NULL) {
delete m_Height;
m_Height = NULL;
}
}
int m_Age;//年龄
int* m_Height;//身高,堆区数据手动开辟也需要手动释放,需要在析构函数释放
};
void test01()
{
Person p(18,160);
cout << "p的年龄为:" << p.m_Age << endl;
cout << "p的身高为:" << *p.m_Height << endl;
Person p2(p);
cout << "p2的年龄为:" << p2.m_Age << endl;
cout << "p2的身高为:" << *p2.m_Height << endl;
}
int main()
{
test01();
}
#include<iostream>
using namespace std;
//初始化列表
class Person
{
public:
//传统的初始化操作
//Person(int a, int b, int c)
//{
// m_A = a;
// m_B = b;
// m_C = c;
//}
//初始化列表初始化属性
Person(int a,int b,int c) :m_A(a), m_B(b), m_C(c)
{
}
int m_A;
int m_B;
int m_C;
};
void test01()
{
//Person p(10, 20, 30);传统初始化方式调用
Person p(30,20,10);
cout << "m_A:" << p.m_A << endl;
cout << "m_B:" << p.m_B << endl;
cout << "m_C:" << p.m_C << endl;
}
int main()
{
test01();
}
class A{}
class B
{
A a;
}
B类中有对象A作为成员,A为对象成员 那么当创建B对象时,A和B的构造和析构的顺序时谁先谁后?
#include<iostream>
using namespace std;
//类对象作为类成员
class Phone
{
public:
string m_PName;
Phone(string mName)
{
m_PName = mName;
cout << "Phone的构造函数被调用" << endl;
}
~Phone()
{
cout << "Phone的析构函数被调用" << endl;
}
};
class Person
{
public:
//姓名
string m_Name;
//手机
Phone m_Phone;
//Phone m_Phone = pName,隐式法等于Phone m_Phone(pName)
Person(string name, string pName):m_Name(name),m_Phone(pName)
{
cout << "Person的构造函数被调用" << endl;
}
~Person()
{
cout << "Person的析构函数被调用" << endl;
}
};
void test01()
{
Person p("张三", "苹果");
cout << p.m_Name << "拿着:" << p.m_Phone.m_PName <<"手机"<< endl;
}
int main()
{
test01();
}
/*
输出结果,说明Phone的构造函数先被调用,Person的析构函数先被调用
Phone的构造函数被调用
Person的构造函数被调用
张三拿着:苹果手机
Person的析构函数被调用
Phone的析构函数被调用
*/
#include<iostream>
using namespace std;
class Person
{
public:
/*
* 所有对象共享同一份数据
* 在编译阶段分配内存
* 类内声明,类外初始化
*/
static int m_A;
//静态成员变量也是有访问权限的
private:
static int m_B;
};
int Person::m_B = 200;//会报错,因为m_B是私有作用域下的。类外访问不到私有的成员变量
int Person::m_A = 100;//Person作用域下
void test01()
{
Person p;
cout << p.m_A << endl;
Person p2;
p2.m_A = 200;
cout << p.m_A << endl;//输出结果是200,说明static是所有对象共享的数据
}
void test02()
{
//静态成员变量 不属于某个对象上,所有对象都共享同一份数据
//因此静态成员变量有两种访问方式
//1.通过对象进行访问
Person p;
cout << p.m_A << endl;
//2.通过类名进行访问
cout << Person::m_A << endl;
}
int main()
{
//test01();
test02();
}
#include<iostream>
using namespace std;
//静态成员函数
//所有对象都共享同一个函数
//静态成员函数只能访问静态成员变量
class Person
{
public:
//静态成员函数
static void func()
{
m_A = 100;//静态成员函数可以访问静态成员变量
//m_B = 200;//报错,静态成员变量不可以访问非静态成员变量
cout << "static void func调用" << endl;
}
static int m_A;
int m_B;
//静态成员函数也是有访问权限的
private:
static void func2()
{
cout << "static func2调用" << endl;
}
};
int Person::m_A = 0;
void test01()
{
//通过对象访问
Person p;
p.func();
//通过类名访问
Person::func();
Person::func2();//报错,类外访问不到私有的静态成员函数。
}
int main()
{
test01();
}
#include<iostream>
using namespace std;
//成员变量和成员函数分开存储
class Person
{
int m_A;//非静态成员变量,输出结果4
static int m_B;//静态成员变量 不属于类对象,所以输出结果4
void func() {}//非静态成员函数,不属于类对象上
static void func2() {}//静态成员函数,也不属于类对象上
};
int Person::m_B = 0;
void test01()
{
Person p;
//空对象占用内存空间为1个字节
//c++编译器会给每个空对象也分配一个字节空间,是为了区分空对象占内存的位置。
cout << "size of p=" << sizeof(p) << endl;
}
int main()
{
test01();
}
#include<iostream>
using namespace std;
//空指针调用成员函数
class Person
{
public:
void showClassName()
{
cout << "this is Person class" << endl;
}
void showPersonAge()
{
//报错原因是因为传入的指针式NULL,一般加上这一句
if (this == NULL)
{
return;
}
cout << "age = " << m_Age << endl;
}
int m_Age;
};
void test01()
{
Person* p = NULL;
p->showClassName();//这个是正常调用
p->showPersonAge();//这个会崩溃,因为
}
int main()
{
test01();
}
#include<iostream>
using namespace std;
//常函数
class Person
{
public:
void showPerson()const//在成员函数后加const,修饰的是this指向,让指针指向的值也不可以修改
{
//this指针的本质时指针常量,指针的指向时不可以修改的
//函数声明后加const相当于const Person * const this;这时候指针指向的值也不可以下修改了
m_A = 100;//函数声明时,后面加了const意味着这是一个常函数,常函数不能修改属性
m_B = 200;
}
void test02()
{
}
int m_A;
mutable int m_B;//特殊变量,即使在常函数中,这个属性仍然可以修改
};
//常对象
void test02()
{
const Person p;//在对象前加const,变为常对象
p.m_A = 100;
p.m_B = 100;//m_B是特殊的值,在常对象下也可以修改
//常对象只可以调用常函数
p.showPerson();
//p.test02();//无法调用,因为test02不是常函数,常对象无法调用非常函数。
}
生活中你的家有客厅(public),有你的卧室(Private) 客厅中所有客人都可以进入,但是卧室是私有的,也就是说只有你能进入 但是,你也可以允许你的好朋友进入。在程序中,有些私有属性也想让类外特殊的一些函数或者类进行访问, 就需要用到友元的技术 友元的目的就是让一个函数或者类访问另一个类中私有成员 友元的关键字为friend 友元的三种实现
#include<iostream>
using namespace std;
class Building
{
//goodGay全局函数是Building的好朋友,可以访问building类的私有成员
friend void googGay(Building* building);
public:
string m_SittingRoom;//客厅
private:
string m_BedRoom;//卧室
public:
Building()
{
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
};
//全局函数
void googGay(Building* building)
{
cout << "好基友的全局函数 正在访问" << building->m_SittingRoom << endl;
cout << "好基友的全局函数 正在访问" << building->m_BedRoom << endl;
}
void test01()
{
Building building;
googGay(&building);
}
int main()
{
test01();
}
#include<iostream>
using namespace std;
//类做友元
class Building;
class GoodGay
{
public:
GoodGay();
public:
void visit();//参观函数,访问building中的属性
Building* building;
};
class Building
{
friend class GoodGay;//GoodGay类是本类好朋友
public:
Building();
public:
string m_SittingRoom;//客厅
private:
string m_BedRoom;//卧室
};
//类外写成员函数
Building::Building()
{
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
GoodGay::GoodGay()
{
//创建一个建筑物对象
building = new Building;
}
void GoodGay::visit()
{
cout << "好基友类正在访问" << building->m_SittingRoom << endl;
cout << "好基友类正在访问" << building->m_BedRoom << endl;
}
void test01()
{
GoodGay gg;
gg.visit();
}
int main()
{
test01();
}
#include<iostream>
using namespace std;
class Building;
class GoodGay
{
public:
GoodGay();
void visit();//让visit函数可以访问Buidlding中私有成员
void visit2();//visit2函数不可以访问Building中私有成员
Building* building;
};
class Building
{
friend void GoodGay::visit();//告诉编译器GoodGay成员函数作为本类的好朋友,可以访问私有内容。
public:
Building();
public:
string m_SittingRoom;//客厅
private:
string m_BedRoom;//卧室
};
//类外实现成员函数
Building::Building()
{
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
GoodGay::GoodGay()
{
building = new Building;
}
void GoodGay::visit()
{
cout << "visit正在访问" << building->m_SittingRoom << endl;
cout << "visit正在访问" << building->m_BedRoom << endl;
}
void GoodGay::visit2()
{
cout << "visit2正在访问" << building->m_SittingRoom << endl;
//cout << "visit正在访问" << building.m_BedRoom << endl;
}
void test01()
{
GoodGay gg;
gg.visit();
gg.visit2();
}
int main()
{
test01();
}
运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型
#include<iostream>
using namespace std;
//加号运算符重载
//成员函数重载+号
class Person
{
public:
int m_A;
int m_B;
public:
Person()
{
m_A = 10;
m_B = 20;
}
//Person operator+(Person& p)
//{
// Person temp;
// temp.m_A = this->m_A + p.m_A;
// temp.m_B = this->m_B + p.m_B;
// return temp;
//}
};
//全局函数重载+号
Person operator+(Person& p1, Person& p2)
{
Person temp;
temp.m_A = p1.m_A + p2.m_A;
temp.m_B = p1.m_B + p2.m_B;
return temp;
}
//函数重载的版本
Person operator+(Person& p1, int num)
{
Person temp;
temp.m_A = p1.m_A + num;
temp.m_B = p1.m_B + num;
return temp;
}
void test01()
{
Person p1;
Person p2;
Person p3 = p1 + p2;
cout << "p3.m_A:" << p3.m_A << endl;
cout << "p3.m_B:" << p3.m_B << endl;
//运算符重载,也可以发生函数重载
Person p4 = p1 + 10;
cout << "p4.m_B:" << p4.m_B << endl;
}
int main()
{
test01();
}
#include<iostream>
using namespace std;
class Person
{
friend ostream& operator<< (ostream& cout, Person& p);//本质opeartor<<(cout,p)简化cout<<p
public:
Person(int a, int b)
{
m_A = a;
m_B = b;
}
private:
int m_A;
int m_B;
//利用成员函数重载左移运算符,通常不会利用成员函数重载左移运算符,因为无法让p在右边
};
//只能用全局函数重载左移运算符
ostream& operator<< (ostream & cout, Person & p)//本质opeartor<<(cout,p)简化cout<<p
{
cout << "m_A = " << p.m_A << " m_B = " << p.m_B;
return cout;
}
void test01()
{
Person p(10,20);
cout << p << endl;
}
int main()
{
test01();
}
总结:重载左移运算符配合友元可以实现输出自定义数据类型 3. 递增运算符重载++
#include<iostream>
using namespace std;
//重载递增运算符
//自定义整型
class MyInteger
{
friend ostream& operator<< (ostream& cout, MyInteger inter);
public:
MyInteger()
{
m_Num = 0;
}
//重载前置++运算符
MyInteger& operator++()
{
m_Num++;
return *this;
}
//重载后置++运算符
//void operator++(int) int 代表占位参数,可以用于区分前置和后置递增
MyInteger operator++(int)
{
//先记录一下当时结果
MyInteger temp = *this;
//后递增
m_Num++;
//最后将记录的结果返回
return temp;
}
/*
注意,后置递增返回的是值,而前置递增返回的是引用,原因如下
前置递增返回引用:如果返回值的话++(++a)这种代码就只会执行一次++因为第二次的++对象已经变了
后置递增返回值:因为后置递增temp是临时变量,不能返回临时变量的引用*/
private:
int m_Num;
};
//只能使用全局函数重载左移运算符
ostream& operator<< (ostream& cout, MyInteger inter)
{
cout << "MyInter.inter:" << inter.m_Num << endl;
return cout;
}
void test01()
{
MyInteger myint;
cout << myint << endl;
//cout << ++myint << endl;
cout << myint++ << endl;
cout << myint << endl;
}
int main()
{
test01();
}
#include<iostream>
using namespace std;
class MyImpuse
{
friend ostream& operator<<(ostream& cout, MyImpuse impuse);
public:
MyImpuse()
{
m_Int = 10;
}
private:
int m_Int;
public:
//前置--运算符的重载
MyImpuse& operator--()
{
m_Int--;
return *this;
}
//后置--运算符的重载
MyImpuse operator--(int)
{
MyImpuse temp = *this;
m_Int--;
return temp;
}
};
//左移运算符的重载
ostream& operator<<(ostream& cout, MyImpuse impuse)
{
cout << "impuse.m_Int:" << impuse.m_Int << endl;
return cout;
}
void test01()
{
MyImpuse p;
cout << p << endl;
cout << --p << endl;
cout << --(--p) << endl;
cout << p-- << endl;
cout << p << endl;
}
int main()
{
test01();
}
#include<iostream>
using namespace std;
//赋值运算符重载
class Person
{
public:
Person(int age)
{
m_Age = new int(age);
}
int* m_Age;
~Person()
{
if (m_Age != NULL)
{
delete m_Age;
m_Age = NULL;
}
}
//重载 赋值运算符
Person& operator=(Person& p)
{
//编译器提供的是浅拷贝
//m_Age = p.m_Age
//应该判断是否有属性在堆区,如果有先释放干净,然后再深拷贝
if (m_Age != NULL)
{
delete m_Age;
m_Age = NULL;
}
//深拷贝
m_Age = new int(*p.m_Age);
return *this;
}
};
void test01()
{
Person p1(18);
cout << "p1的年龄为:" << *p1.m_Age << endl;
Person p2(20);
p2 = p1;//赋值操作
cout << "p2的年龄为:" << *p2.m_Age << endl;
Person p3(30);
p3 = p2 = p1;
cout << "p3的年龄为:" << *p3.m_Age << endl;
}
int main()
{
test01();
}
#include<iostream>
using namespace std;
//重载关系运算符
class Person
{
public:
Person(string name, int age)
{
m_Name = name;
m_Age = age;
}
string m_Name;
int m_Age;
//重载==,同理也可以重载!=
bool operator==(Person& p)
{
if (p.m_Age == this->m_Age&&p.m_Name == this->m_Name)
{
return true;
}
else
{
return false;
}
}
};
void test01()
{
Person p1("Tom", 18);
Person p2("李四", 18);
if (p1 == p2)
{
cout << "p1和p2相等" << endl;
}
else
{
cout << "p1和p2不相等" << endl;
}
}
int main()
{
test01();
}
#include<iostream>
using namespace std;
//函数调用运算符重载
//打印输出类
class MyPrint
{
public:
//重载函数调用运算符
void operator()(string test)
{
cout << test << endl;
}
};
void test01()
{
MyPrint myPrint;
myPrint("hello world");//使用起来非常像函数调用,因此称为仿函数。
}
//仿函数非常灵活,没有固定的写法
//加法类
class MyAdd
{
public:
int operator()(int num1, int num2)
{
return num1 + num2;
}
};
void test02()
{
MyAdd myadd;
int ret = myadd(100, 100);
cout << "ret=" << ret << endl;
//匿名函数对象,用完对象就被清理
cout << MyAdd()(100, 100) << endl;
}
int main() {
test02();
}
继承是面向对象三大特性之一
有些类与类之间存在特殊的关系,例如下图中:
我们发现,定义这些类型时,下级别的成员除了拥有上级别的共性,还有自己的特性
这个时候我们就可以考虑利用继承的技术,减少重复代码
例如我们看到的很多网站中,都有公共的头部,公共的底部,甚至公共的左侧列表,只有中心内容不同,接下来
我们分别利用普通写法和继承写法来实现网页中的内容,看一下继承存在的意义以及好处。
#include<iostream>
using namespace std;
//普通实现页面
//Java页面
//class Java
//{
//public:
// void header()
// {
// cout << "首页 公开课 登录 注册(公共头部)" << endl;
// }
// void footer()
// {
// cout << "帮助中心 交流合作 站内地图(公共底部)" << endl;
// }
// void left()
// {
// cout << "java python c++(公共分类列表)" << endl;
// }
// void content()
// {
// cout << "java 学科视频" << endl;
// }
//
//};
//继承方式实现
//公共页面类
class BasePage
{
public:
void header()
{
cout << "首页 公开课 登录 注册(公共头部)" << endl;
}
void footer()
{
cout << "帮助中心 交流合作 站内地图(公共底部)" << endl;
}
void left()
{
cout << "java python c++(公共分类列表)" << endl;
}
};
//继承的好处:减少重复的代码
// 语法:class子类:继承方式 父类
// 子类 也称为派生类
// 父类 也称为基类
//java页面
class Java : public BasePage
{
public:
void content()
{
cout << "Java学科视频" << endl;
}
};
//python页面
class Python :public BasePage
{
public:
void content()
{
cout << "python学科视频" << endl;
}
};
//c++页面
class Cpp :public BasePage
{
public:
void content()
{
cout << "c++学科视频" << endl;
}
};
void test01()
{
cout << "Java下载视频页面如下:" << endl;
Java ja;
ja.header();
ja.footer();
ja.left();
ja.content();
cout << "python下载视频页面如下:" << endl;
Python py;
py.header();
py.footer();
py.left();
py.content(); cout << "c++下载视频页面如下:" << endl;
Cpp c;
c.header();
c.footer();
c.left();
c.content();
}
int main()
{
test01();
}
派生类的成员,包含两大部分:
一类时从基类继承过来的,一类时自己增加的成员
从基类继承过来的表现其共性,而新增的成员体现了其个性
继承的语法:class 子类:继承方式 父类
继承方式三种:
#include<iostream>
using namespace std;
//继承方式
//公共继承
class Base1
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son1 :public Base1
{
public:
void func()
{
m_A = 10;//父类中公共权限成员,到子类中仍然受公共权限
m_B = 10;//父类中保护权限成员,到子类中依然是保护权限
//m_C = 10;//父类中私有权限成员,到子类中访问不到
}
};
void test01()
{
Son1 s1;
s1.m_A = 100;
//s1.m_B = 100;//保护权限访问不到
}
//保护继承
class Base2
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son2 :protected Base2
{
public:
void func()
{
m_A = 100;//父类中公共成员,到子类中变为保护权限
m_B = 100;
//m_C = 100;//父类中私有成员,子类访问不到
}
};
void test02()
{
Son2 s1;
s1.m_A = 100;//保护继承,所以m_A变成保护权限,因此类外访问不到
s1.m_B = 200;//保护继承,m_B 变成保护权限,类外访问不到
}
class Base3
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son3 :private Base3
{
public:
void func()
{
m_A = 100;//父类中公共成员,到子类中变为私有成员
m_B = 100;//父类中保护成员,到子类中变为私有成员
m_C = 100;//父类中私有成员,子类访问不到
}
};
void test03()
{
Son3 s1;
s1.m_A = 100;//私有成员,类外访问不到,下同
s1.m_B = 100;//
s1.m_B = 100;//
}
class GrandSon3 :public Son3
{
public:
void func()
{
m_A = 1000;//报错,这是Son3中私有成员,无论GrandSon如何继承,都访问不到
}
};
int main()
{
test03;
}
问题:从父类继承过来的成员,哪些属于子类对象中
实例:
#include<iostream>
using namespace std;
//继承中的对象模型
class Base
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son :public Base
{
public:
int m_D;
};
void test01()
{
cout << "size of Son=" << sizeof(Son) << endl;
//输出结果是size of Son=16,意思其实是无论父类是什么属性都会被子类继承下去
//但是父类中私有成员属性是被编译器隐藏了,因此是访问不到,但是确实是继承下去了。
}
int main()
{
test01();
}
//利用开发人员命令提示工具查看对象模型
//跳转盘符F:
//跳转到文件路径cd具体路径下
//查看命名
// c1/d1 reportSingleClassLayout类名 "文件名.cpp"
/*
源.cpp
class Son size(16):
+---
0 | +--- (base class Base)
0 | | m_A
4 | | m_B
8 | | m_C
| +---
12 | m_D
+---
*/
结论:父类中私有成员也是被子类继承下去了,只是由编译器给隐藏后访问不到
子类继承父类后,当创建子类对象,也会调用子类的构造函数
问题:父类和子类的构造和析构顺序
实例:
#include<iostream>
using namespace std;
//继承中的构造和析构顺序
class Base
{
public:
Base()
{
cout << "Base构造函数" << endl;
}
~Base()
{
cout << "Base析构函数" << endl;
}
};
class Son :public Base
{
public:
Son()
{
cout << "Son构造函数!" << endl;
}
~Son()
{
cout << "Son析构函数!" << endl;
}
};
void test01()
{
Son s;
//继承中的析构和构造顺序如下:
//先构造父类,在构造子类,析构顺序和构造顺序相反
/*
Base构造函数
Son构造函数!
Son析构函数!
Base析构函数
*/
}
int main()
{
test01();
}
总结:继承中先调用父类构造函数,再调用子类构造函数,析构顺序和构造相反
问题:当子类与父类出现同名的成员,如何通过子类对象,访问到子类成父类中的数据呢?
#include<iostream>
using namespace std;
//继承中同名成员处理
class Base
{
public:
Base()
{
m_A = 100;
}
void func()
{
cout << "Base - func()调用" << endl;
}
int m_A;
};
class Son :public Base
{
public:
Son()
{
m_A = 200;
}
void func()
{
cout << "Son - func()调用" << endl;
}
int m_A;
};
void test01()
{
Son s;
cout << "Son m_A=" << s.m_A << endl;
//如果通过子类对象访问到父类中同名成员,需要加作用域
cout << "Base m_A=" << s.Base::m_A << endl;
/*
Son m_A=200
Base m_A=100
*/
}
//同名函数处理
void test02()
{
Son s;
s.func();
s.Base::func();
//如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数
/*
Son - func()调用
Base - func()调用
*/
}
int main()
{
//test01();
test02();
}
总结:
问题:继承中同名的静态成员在子类对象上如何进行访问? 静态成员和非静态成员出现同名,处理方式一致
#include<iostream>
using namespace std;
//继承中的同名静态成员处理方式
class Base
{
public:
static int m_A;
static void func()
{
cout << "Base - static void func()" << endl;
}
};
int Base::m_A = 1200;
class Son :public Base
{
public:
static int m_A;
static void func()
{
cout << "Son - static void func()" << endl;
}
};
int Son::m_A = 200;
//同名静态成员属性
void test01()
{
//通过对象访问数据
cout << "通过对象方式访问:" << endl;
Son s;
cout << "Son m_A=" << s.m_A << endl;
cout << "Base m_A=" << s.Base::m_A << endl;
//通过类名访问数据
cout << "通过类名访问:" << endl;
cout << "Son m_A=" << Son::m_A << endl;
//第一个::代表通过类名的方式访问 第二个::代表访问父类作用域下
cout << "Base m_A=" << Son::Base::m_A << endl;
}
//同名静态函数
void test02()
{
//通过对象方式访问
Son s;
s.func();
s.Base::func();
//通过类名方式访问
Son::func();
Son::Base::func();
//子类出现和父类同名静态成员函数,也会隐藏父类中所有同名成员函数
//如果想访问父类中被隐藏同名成员,需要加作用域
}
int main()
{
//test01();
test02();
}
c允许一个类继承多个类
语法:class 子类:继承方式 父类1,继承方式 父类2...
多继承可能会引发父类中有同名成员出现,需要加作用域区分
C实际开发中不建议使用多继承
#include<iostream>
using namespace std;
//多继承语法
class Base1
{
public:
Base1()
{
m_A = 100;
}
int m_A;
};
class Base2
{
public:
Base2()
{
m_A = 200;
}
int m_A;
};
//子类 需要继承Base1和Base2
class Son :public Base1, public Base2
{
public:
Son()
{
m_C = 300;
m_D = 400;
}
int m_C;
int m_D;
};
void test01()
{
Son s;
cout << "sizeof Son = " << sizeof(s) << endl;
//cout << "m_A = " << s.m_A << endl;
//当父类出现同名成员,需要加作用域区分
cout << "Base1::m_A = " << s.Base1::m_A << endl;
cout << "Base2::m_B = " << s.Base2::m_A << endl;
}
int main()
{
test01();
}
总结:多继承中如果父类中出现了同名情况,子类使用时要加作用域。
菱形继承概念:
两个派生类继承同一个基类
又有某个类同时继承自两个派生类
这种继承称为菱形继承,或者钻石继承
典型菱形继承案例:
菱形继承问题:
#include<iostream>
using namespace std;
//动物类
class Animal {
public:
int m_Age;
};
//利用虚继承可以解决菱形继承的问题
//继承之前加上关键字virtual变成虚继承
//Animal类称为虚基类
//羊类
class Sheep :virtual public Animal {};
//驼类
class Tuo :virtual public Animal {};
//羊驼类
class SheepTuo :public Sheep, public Tuo {};
void test01()
{
SheepTuo st;
st.Sheep::m_Age = 18;
st.Tuo::m_Age = 29;
//当菱形继承时,两个父类拥有相同的数据,需要加以作用域区分
cout << "st.Sheep::m_Age=" << st.Sheep::m_Age << endl;
cout << "st.Tuo::m_Age=" << st.Tuo::m_Age << endl;
cout << "st.m_Age=" << st.Tuo::m_Age << endl;
/*
st.Sheep::m_Age=29
st.Tuo::m_Age=29
st.m_Age=29
*/
//这份数据我们只要一份就可以了,菱形继承导致数据有两份,资源浪费。
}
int main()
{
test01();
}
/*
class SheepTuo size(8):
+---
0 | +--- (base class Sheep)
0 | | +--- (base class Animal)
0 | | | m_Age
| | +---
| +---
4 | +--- (base class Tuo)
4 | | +--- (base class Animal)
4 | | | m_Age
| | +---
| +---
+---
*/
//使用虚继承之后
/*
class SheepTuo size(12):
+---
0 | +--- (base class Sheep)
0 | | {vbptr}
| +---
4 | +--- (base class Tuo)
4 | | {vbptr}
| +---
+---
+--- (virtual base Animal)
8 | m_Age
+---
SheepTuo::$vbtable@Sheep@:
0 | 0
1 | 8 (SheepTuod(Sheep+0)Animal)
SheepTuo::$vbtable@Tuo@:
0 | 0
1 | 4 (SheepTuod(Tuo+0)Animal)
vbi: class offset o.vbptr o.vbte fVtorDisp
Animal 8 0 4 0
*/
//所谓的vbptr是虚基类指针,指向一个vbtable(虚基类表)
总结:
多态是C++面向对象三大特性之一
多态分为两类
#include<iostream>
using namespace std;
//多态
//动物类
class Animal
{
public:
//虚函数
virtual void speak()
{
cout << "动物在说话" << endl;
}
//public:
// void speak()
// {
// cout << "动物在说话" << endl;
// }
};
class Cat :public Animal
{
public:
void speak()
{
cout << "小猫在说话" << endl;
}
};
//狗类
class Dog :public Animal
{
public:
void speak()
{
cout << "小狗在说话" << endl;
}
};
//执行说话的函数
//地址早绑定,在编译阶段就确定了函数地址
//如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,叫晚绑定
//动态多态满足条件
//1. 有继承关系
//2. 子类要重写父类的虚函数(重写:函数返回值类型,函数名,参数列表完全相同)
//动态多态的使用
//父类的指针或者引用执行子类对象
void doSpeak(Animal &animal)//父类的引用接受子类的对象Animal& animal = cat;
{
animal.speak();
}
void test01()
{
Cat cat;
doSpeak(cat);
Dog dog;
doSpeak(dog);
/*
小猫在说话
小狗在说话
*/
}
int main()
{
test01();
}
总结:
多态满足条件
#include<iostream>
using namespace std;
class Animal
{
public:
virtual void speak()
{
cout << "动物说话。" << endl;
}
/*
* 虚函数的情况
class Animal size(4):
+---
0 | {vfptr}
+---
Animal::$vftable@:
| &Animal_meta
| 0
0 | &Animal::speak
Animal::speak this adjustor: 0
*/
//void speak()
//{
// cout << "动物说话。" << endl;
//}
/*
非虚函数的情况
class Animal size(1):
+---
+---
*/
/*
由此可见*/
};
class Cat :public Animal
{
public:
/*
子类没有发生重写时
class _s__CatchableType size(28):
+---
0 | properties
4 | pType
8 | _PMD thisDisplacement
20 | sizeOrOffset
24 | copyFunction
+---
class _s__CatchableTypeArray size(4):
+---
0 | nCatchableTypes
4 | arrayOfCatchableTypes
+---
class Cat size(4):
+---
0 | +--- (base class Animal)
0 | | {vfptr}
| +---
+---
Cat::$vftable@:
| &Cat_meta
| 0
0 | &Animal::speak//注意此处是Animal的speak函数
*/
void speak()
{
cout << "猫在说话。" << endl;
}
/*
子类发生重写时
class _s__CatchableType size(28):
+---
0 | properties
4 | pType
8 | _PMD thisDisplacement
20 | sizeOrOffset
24 | copyFunction
+---
class _s__CatchableTypeArray size(4):
+---
0 | nCatchableTypes
4 | arrayOfCatchableTypes
+---
class Cat size(4):
+---
0 | +--- (base class Animal)
0 | | {vfptr}
| +---
+---
Cat::$vftable@:
| &Cat_meta
| 0
0 | &Cat::speak//此处被覆盖成猫的speak函数
Cat::speak this adjustor: 0
*/
};
void doSpeak(Animal &animal)//父类的引用接受子类的对象Animal& animal = cat;
{
animal.speak();
}
void test01()
{
Cat cat;
doSpeak(cat);
Dog dog;
doSpeak(dog);
/*
小猫在说话
小狗在说话
*/
}
int main()
{
test01();
}
案例描述:
分别利用普通写法和多态技术,设计实现两个操作数进行运算计算器类
多态的优点:
#include<iostream>
using namespace std;
////普通实现
//class Calculator
//{
//public:
// int getResult(string oper)
// {
// if (oper == "+")
// {
// return m_Num1 + m_Num2;
// }
// else if (oper == "-")
// {
// return m_Num1 - m_Num2;
// }
// else if (oper == "*")
// {
// return m_Num1 * m_Num2;
// }
// //如果想扩展新的功能,需要修改源码,在真实的开发中,提倡开闭原则(对扩展进行开放,对修改进行关闭)
// }
// int m_Num1;//操作数1
// int m_Num2;//操作数2
//};
//void test01()
//{
// //创建计算器对象
// Calculator c;
// c.m_Num1 = 10;
// c.m_Num2 = 10;
// cout << c.m_Num1 << "+" << c.m_Num2 << "=" << c.getResult("+") << endl;
// cout << c.m_Num1 << "-" << c.m_Num2 << "=" << c.getResult("-") << endl;
// cout << c.m_Num1 << "*" << c.m_Num2 << "=" << c.getResult("*") << endl;
//}
//利用多态实现计算器
//实现计算器的基类(抽象类)
class AbstractCalculator
{
public:
int m_Num1;
int m_Num2;
virtual int getResult()
{
return 0;
}
};
//加法计算器类
class AddCalculator :public AbstractCalculator
{
int getResult()
{
return m_Num1 + m_Num2;
}
};
//减法计算器类
class SubCalculator :public AbstractCalculator
{
int getResult()
{
return m_Num1 - m_Num2;
}
};
//乘法计算器类
class MulCalculator :public AbstractCalculator
{
public:
int getResult()
{
return m_Num1 * m_Num2;
}
};
void test02()
{
//多态使用条件
//父类指针或者引用指向子类对象
AbstractCalculator* abc = new AddCalculator;
abc->m_Num1 = 10;
abc->m_Num2 = 20;
cout << abc->m_Num1 << "+" << abc->m_Num2 << "=" << abc->getResult() << endl;
//堆区的数据手动开辟手动销毁
delete abc;//这是把堆区的数据释放了
//减法运算
abc = new SubCalculator;
abc->m_Num1 = 10;
abc->m_Num2 = 20;
cout << abc->m_Num1 << "-" << abc->m_Num2 << "=" << abc->getResult() << endl;
delete abc;
//乘法运算
abc = new MulCalculator;
abc->m_Num1 = 10;
abc->m_Num2 = 20;
cout << abc->m_Num1 << "*" << abc->m_Num2 << "=" << abc->getResult() << endl;
}
//多态带来的好处
//1.组织结构清晰
//2.可读性强
//3.对于后期和前期扩展以及维护性高
int main()
{
test02();
}
在多态中,通常父类中虚函数的实现是无意义的,主要都是调用子类重写的内容
因此可以将虚函数改为纯虚函数
纯虚函数语法 virtual 返回值类型 函数名 (参数列表) = 0;
当类中有了纯虚函数,这个类也成为抽象类
抽象类特点:
#include<iostream>
using namespace std;
//纯虚函数和抽象类
class Base
{
public:
//纯虚函数
//只要有一个纯虚函数,这个类称为抽象类
//抽象类特点:
//1.无法实例化对象
//2.子类必须重写父类纯虚函数,否则也是抽象类
virtual void func() = 0;
};
class Son :public Base
{
public:
virtual void func() {
cout<< "func函数的调用" << endl;
};
};
void test01()
{
//Base b抽象类无法实例化对象
//new Base抽象类无法实例化对象
//Son s;//子类必须重写父类中的纯虚函数,否则无法实例化对象
Base* base = new Son;
base->func();
}
int main()
{
test01();
}
案例描述:
制作饮品的大致流程:煮水,冲泡,倒入杯中,加入辅料
利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶
#include<iostream>
using namespace std;
//多态案例2制作饮品
class AbstractDrinking
{
public:
//煮水
virtual void Boil() = 0;
//冲泡
virtual void Brew() = 0;
//倒入杯中
virtual void PourInCup() = 0;
//加入辅料
virtual void PutSomething() = 0;
//制作饮品
void makeDrink()
{
Boil();
Brew();
PourInCup();
PutSomething();
}
};
//制作咖啡
class Coffee :public AbstractDrinking
{
public:
virtual void Boil()
{
cout << "煮农夫山泉" << endl;
}
//冲泡
virtual void Brew()
{
cout << "冲泡咖啡" << endl;
}
//倒入杯中
virtual void PourInCup()
{
cout << "倒入杯中" << endl;
}
//加入辅料
virtual void PutSomething()
{
cout << "加入辅料糖和牛奶" << endl;
}
};
//制作茶叶
class Tea :public AbstractDrinking
{
public:
virtual void Boil()
{
cout << "煮自来水" << endl;
}
//冲泡
virtual void Brew()
{
cout << "冲泡茶叶" << endl;
}
//倒入杯中
virtual void PourInCup()
{
cout << "倒入杯中" << endl;
}
//加入辅料
virtual void PutSomething()
{
cout << "加入柠檬和枸杞" << endl;
}
};
//制作函数
void doWork(AbstractDrinking* abs)
{
abs->makeDrink();
delete abs;
}
void test01()
{
//制作咖啡
doWork(new Coffee);
//制作茶叶
cout << "------------" << endl;
doWork(new Tea);
}
int main()
{
test01();
}
多态使用是,如果子类有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
解决办法:将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构共性:
#include<iostream>
using namespace std;
//纯虚析构和虚析构
class Animal
{
public:
virtual void speak() = 0;
Animal()
{
cout << "Animal构造函数调用" << endl;
}
//虚析构
//virtual ~Animal()
//{
// cout << "Animal析构函数被调用" << endl;
//}
//纯虚析构
//有纯虚析构之后,这个类也属于抽象类,无法实例化对象
virtual ~Animal() = 0;
};
Animal::~Animal()
{
cout << "Animal纯虚析构函数被调用" << endl;
}
class Cat :public Animal
{
public:
Cat(string name)
{
cout << "Cat构造函数被调用" << endl;
m_Name = new string(name);
}
virtual void speak()
{
cout << *m_Name<<"小猫在说话" << endl;
}
~Cat()
{
if (m_Name != NULL)
{
cout << "Cat析构函数被调用" << endl;
delete m_Name;
m_Name = NULL;
}
}
string* m_Name;
};
void test01()
{
Animal* animal = new Cat("Tom");
animal->speak();
//父类指针在析构的时候,不会调用子类中析构函数,导致子类如果有堆区属性,会出现内存泄漏
delete animal;
}
int main()
{
test01();
//没有使用虚析构时控制台输出:
/*
Animal构造函数调用
Cat构造函数被调用
Tom小猫在说话
Animal析构函数被调用
*/
//可见没有走Cat的析构函数,所以堆区的内存没有释放干净,导致内存泄漏
//利用虚析构可以解决父类指针释放子类对象时不干净的问题
//使用虚析构时控制台输出:
/*
Animal构造函数调用
Cat构造函数被调用
Tom小猫在说话
Cat析构函数被调用
Animal析构函数被调用
*/
}
总结:
案例描述:
电脑主要组成部分为CPU 显卡 内存条 将每个零件封装出抽象基类,并且提供不同的厂商生产不同的零件,例如Intel 和Lenovo厂商
创建电脑类提供让电脑工作的函数,并且调用每个零件工作的接口
测试时组装三台不同的电脑进行工作
实例:
#include<iostream>
using namespace std;
//抽象CPU
class Cpu
{
public:
virtual void calculate() = 0;
};
//抽象显卡
class VideoCard
{
public:
virtual void display() = 0;
};
//抽象内存条
class Memory
{
public:
virtual void storage() = 0;
};
//电脑类
class Computer
{
public:
//构造函数传入三个零件指针
Computer(Cpu* cpu, VideoCard* vc, Memory* st)
{
m_cpu = cpu;
m_vc = vc;
m_st = st;
}
//提供一个工作函数
void doWork()
{
m_cpu->calculate();
m_vc->display();
m_st->storage();
}
//提供一个析构函数,释放零件的内存
~Computer()
{
if (m_cpu != NULL)
{
delete m_cpu;
m_cpu = NULL;
}
if (m_vc != NULL)
{
delete m_vc;
m_vc = NULL;
}
if (m_st != NULL)
{
delete m_st;
m_st = NULL;
}
}
private:
Cpu* m_cpu;
VideoCard* m_vc;
Memory* m_st;
};
//具体厂商
//Intel厂商
class IntelCpu :public Cpu
{
public:
virtual void calculate()
{
cout << "Intel的cpu开始计算了" << endl;
}
};
class IntelVideoCard :public VideoCard
{
public:
virtual void display()
{
cout << "Intel的显卡开始显示了" << endl;
}
};
class IntelMemory :public Memory
{
public:
virtual void storage()
{
cout << "Intel的内存条开始工作了" << endl;
}
};
class LenovoCpu :public Cpu
{
void calculate()
{
cout << "联想的cpu开始工作了" << endl;
}
};
class LenovoVideoCard :public VideoCard
{
void display()
{
cout << "联想的显卡开始工作了" << endl;
}
};
class LenovoMemory :public Memory
{
void storage()
{
cout << "联想的内存条开始工作了" << endl;
}
};
//组装不同的电脑
void test01()
{
//第一台电脑零件
Cpu* intelCpu = new IntelCpu;
VideoCard* interCard = new IntelVideoCard;
Memory* intelMem = new IntelMemory;
//创建第一个电脑
cout << "-------------------------" << endl;
cout << "第一台电脑开始工作" << endl;
Computer* computer1 = new Computer(intelCpu, interCard, intelMem);
computer1->doWork();
delete computer1;
//创建第二台电脑
cout << "-------------------------" << endl;
cout << "第二台电脑开始工作" << endl;
Computer* computer2 = new Computer(new LenovoCpu, new LenovoVideoCard, new IntelMemory);
computer2->doWork();
}
int main()
{
test01();
}
程序运行时产生的数据属于临时数据,程序一旦运行结束就会被释放
通过文件可以将数据持久化
c++中对文件操作需要包含头文件
写文件步骤如下:
#include<iostream>
using namespace std;
#include<fstream>//头文件的包含
//文本文件写文件
void test01()
{
//包含头文件,fstream
//创建输出流对象
ofstream ofs;
//指定打开方式
ofs.open("test.txt", ios::out);//不指定路径则默认创建在项目路径下
//写内容
ofs << "姓名:张三" << endl;
ofs << "性别:男" << endl;
ofs << "年龄:18" << endl;
//关闭文件
ofs.close();
}
int main()
{
test01();
}
总结:
读文件与写文件步骤类似,但是读取方式相对于比较多
读文件步骤如下:
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
void test01()
{
//创建流对象
ifstream ifs;
//打开文件,判断是否打开成功
ifs.open("test.txt", ios::in);
if (!ifs.is_open())
{
cout << "文件打开失败" << endl;
return;
}
//读数据
//第一种
//char buf[1024] = { 0 };
//while (ifs>>buf)
//{
// cout << buf << endl;
//}
////关闭文件
//ifs.close();
//第二种
/*char buf[1024] = { 0 };
while (ifs.getline(buf,sizeof(buf)))
{
cout << buf << endl;
}
ifs.close();*/
//第三种
//string buf;
//while (getline(ifs,buf))
//{
// cout << buf << endl;
//}
//ifs.close();
//第四种,不太推荐了,效率慢
char c;
while ((c=ifs.get()) != EOF)//EOF是文件尾的意思
{
cout << c;
}
ifs.close();
}
int main()
{
test01();
}
以二进制的方式对文件进行读写操作
打开方式要指定为los::binary
二进制方式写文件主要是利用流对象调用成员函数write
函数原型:ostream& write(const char* buffer,int len);
参数解释:字符指针buffer指向内存中一段存储空间,len是读写的字节数
实例:
#include<iostream>
using namespace std;
#include<fstream>
//二进制文件写文件
class Person
{
public:
char m_Name[64];//姓名
int m_Age;//年龄
};
void test01()
{
//创建流对象
//也可以在创建对象的时候就初始化
ofstream ofs("person.txt", ios::out | ios::binary);
//打开文件
//ofs.open("person.txt", ios::out | ios::binary);
//写文件
Person p = { "张三",28 };
ofs.write((const char*)&p, sizeof(Person));
//关闭文件
ofs.close();
}
二进制方式读文件主要利用流对象调用成员函数read
函数原型:istream& read(char* buffer,int len);
参数解释:字符指针buffer指向内存中一段存储空间,len是读写的字节数
实例
#include<iostream>
#include<fstream>
using namespace std;
class Person
{
public:
int m_Age;
char m_Name[64];
};
void test01()
{
ifstream ifs;
ifs.open("person.txt", ios::in | ios::binary);
if (!ifs.is_open())
{
cout << "文件打开失败" << endl;
return;
}
//读文件
Person p;
ifs.read( (char*)& p, sizeof(Person));
cout << "姓名:" << p.m_Name << "年龄:"<<p.m_Age << endl;
}
int main()
{
test01();
}
职工管理系统可以用来管理公司内所有员工的信息
本教程主要利用C++来实现一个基于多态的的职工管理系统
公司中职工分为三类:普通员工、经理、老板、显示信息时,需要显示职工编号、职工姓名、职工岗位、以及职责
普通员工的职责:完成经理交给的任务
经理职责:完成老板交给的任务,并下发给员工
老板职责:管理公司所有事物
管理系统中需要实现的功能如下:
创建项目步骤如下:
管理类的负责内容如下:
#pragma once //避免头文件重复包含
#include <iostream>
using namespace std;
class workerManager
{
public:
workerManager();
~workerManager();
};
#include "workerManager.h"
workerManager::workerManager()
{
}
workerManager::~workerManager()
{
}
功能描述:与用户的沟通界面
功能描述:批量添加职工,并且保存到文件中
功能描述:对文件进行读写
在上一个添加功能中,我们只是将所有的数据添加到了内存中,一旦程序结束就无法保存了
因此文件管理类中需要一个与文件进行交互的功能,对于文件进行读写操作
模板的特点:
函数模板作用: 建立一个通用的函数,其函数返回值类型和形参类型不可以具体制定,用一个虚拟的类型来代表。 语法: template
#include<iostream>
using namespace std;
void changeInt(int& a, int& b)
{
int temp = a;
a = b;
b = temp;
}
void changeDouble(double& a, double& b)
{
double temp = a;
a = b;
b = temp;
}
void test01()
{
int a = 10;
int b = 20;
changeInt(a, b);
cout << "a=" << a << endl;
cout << "b=" << b << endl;
double c = 4.95;
double d = 5.52;
changeDouble(c, d);
cout << "c=" <<c<< endl;
cout << "d=" <<d<< endl;
}
//函数模板
template<typename T>//声明一个模板,告诉编译器后面代码中紧跟着T不要报错,T是一个通用的数据类型
void mySwap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
void test02()
{
int a = 10;
int b = 20;
//使用函数模板的两种方式
//1.自动类型推导
mySwap(a, b);
cout << "a=" << a << endl;
cout << "b=" << b << endl;
//2.显示指定类型
mySwap<int>(a, b);
}
int main()
{
//test01();
test02();
}
总结:
注意事项:
template<class T>
void func()
{
cout<<"func 调用"<<endl;
}
void test02()
{
func<int>();//此时必须要用显式指定了,因为没有办法用隐式指定。
}
案例描述:
#include<iostream>
using namespace std;
template<class T>
void mySwap(T& a,T& b)
{
T temp = a;
a = b;
b = temp;
}
template<class T>
void mySort(T arr[], int len)
{
for (int i = 0; i < len; i++)
{
int max = i;
for (int j = i+1; j < len; j++)
{
if (arr[max]<arr[j])
{
max = j;//更新最大值下标
}
}
if (max != i)
{
//交换max和i元素
mySwap(arr[i], arr[max]);
}
}
}
//提供打印数组的模板
template<class T>
void printArray(T arr[], int len)
{
for (int i = 0; i < len; i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
void test01()
{
//测试char数组
char charArr[] = "badrfagahahfshsad";
mySort(charArr, size(charArr));
printArray(charArr, size(charArr));
}
void test02()
{
//测试int数组
int intArr[] = { 4,56,263,36,5474,25,2 };
mySort(intArr, size(intArr));
printArray(intArr, size(intArr));
}
int main()
{
//test01();
test02();
}
普通函数和函数模板的区别:
//普通函数
int myAdd01(int a,int b)
{
return a+b;
}
void test01()
{
int a = 10;
int b = 20;
char c = 'c';
cout<<myAdd01(a,c)<<end;
}//输出109,这个最终输出是不会报错的,因为这里发生了隐式类型转换,将char转换为int
template<class T>
T myAdd02(T a,T b)
{
return a + b;
}
void test01()
{
int a = 10;
int b = 20;
char c = 'c';//
cout<<myAdd02(a,c)<<endl;//这个最终会报错
}
如果把刚才最后一行代码改成:
cout<<myAdd02<int>(a,c)<<endl;//这个不会报错,会发生隐式类型转换,将char转为int
实例:
调用规则如下:
#include<iostream>
using namespace std;
//普通函数和函数模板的调用规则
//如果函数模板和普通函数都可以调用,优先调用函数模板
//可以通过空模板参数列表强制调用函数模板
//函数模板可以发生函数重载
//如果函数模板可以产生更好的匹配,优先调用函数模板
void myPrint(int a, int b)
{
cout << "调用普通函数" << endl;
}
template<class T>
void myPrint(T a, T b,T c)
{
cout << "调用模板" << endl;
}
void test01()
{
int a = 10;
int b = 20;
int c = 30;
myPrint(a, b);//调用函数,即使将函数实现注释了也是一样
//通过空模板参数列表,强制调用函数模板
//myPrint<>(a, b);//调用模板
myPrint(a, b, c);//调用模板
char c1 = 'a';
char c2 = 'b';
myPrint(c1, c2);//要注意普通函数是可以发生隐式类型转换的,所以函数和模板都可以调用,但是调用函数涉及到
//隐式类型转换,为了更方便调用,所以编译器调用模板。
}
int main()
{
test01();
}
实际开发中函数重载和模板不要同时出现,避免二义性
局限性:
template<class T>
void f(T a,T b)
{
a = b;
}
上述代码中提供的赋值操作,如果传入的a和b是一个数组就无法实现了
template
#include<iostream>
using namespace std;
class Person
{
//姓名
public:
Person(string name, int age)
{
this->m_Age = age;
this->m_Name = name;
}
public:
int m_Age;
string m_Name;
};
template<class T>
bool myCompare(T& a, T& b)
{
if (a == b)
{
return true;
}
else
{
return false;
}
}
template<> bool myCompare(Person& p1, Person& p2)
{
if (p1.m_Age == p2.m_Age && p1.m_Name == p2.m_Name)
{
return true;
}
else
{
return false;
}
}
void test01()
{
int a = 10;
int b = 20;
bool ret = myCompare(a, b);
string ss = ret ? "a==b" : "a!=b";
cout << ss << endl;
}
void test02()
{
Person p1("Tom", 110);
Person p2("Tom", 10);
bool ret = myCompare(p1, p2);
string ss = ret ? "p1==p2" : "p1!=p2";
cout << ss << endl;
}
int main()
{
////test01();
test02();//报错
//有两种方法,第一是运算符重载
//第二种方法,利用具体化Person的版本实现代码,具体化优先调用
}
总结:
类模板作用:
template<typename T>
template<class NameType,class AgeType>
class Person
{
public:
Person(NameType name,AgeType age)
{
this->m_Name = name;
this->m_Name = age;
}
void showPerson()
{
cout<<"name"<<this->m_Name<<"age:"this->m_Age<<endl;
}
NameType m_Name;
AgeType m_Age;
}
void test01()
{
Person<string,int>p1("孙悟空",999);
p1.showPerson();
}
总结:类模板和函数模板语法相似,在声明模板template后面加类,此类称为类模板
类模板与函数模板区别主要有两点:
#include<iostream>
using namespace std;
template<class NameType,class AgeTyep>
class Person
{
public:
Person(NameType name, AgeTyep age)
{
this->m_Age = age;
this->m_Name = name;
}
void showPerson()
{
cout << "name:" << this->m_Name << "age:" << this->m_Age << endl;
}
public:
NameType m_Name;
AgeTyep m_Age;
};
//类模板没有自动类型推导的使用方式
void test01()
{
//Person p("孙悟空", 1000);//这是错误的,无法使用自动类型推导
Person<string, int>p("孙悟空", 1000);
}
//类模板在模拟参数列表中可以有默认参数
void test02()
{
//如果前面的template<class NameType,class AgeTyep>写成如下形式:
//template<class NameType,class AgeType=int>那么下面就不用在指定int的类型了
Person<string, int>p("猪八戒", 1000);
}
int main()
{
test01();
}
类模板中成员函数和普通类中成员函数创建实际是有区别的:
#include<iostream>
using namespace std;
//类模板中成员函数只有在调用时才去创建
class Person1
{
public:
void showPerson()
{
cout << "Person1 show" << endl;
}
};
class Person2
{
public:
void showPerson()
{
cout << "Person2 show" << endl;
}
};
template<class T>
class myClass
{
public:
T obj;
//类模板中的成员函数
void func1()
{
obj.showPerson1();
}
void func1()
{
obj.showPerson2();
}
};
void test01()
{
myClass<Person1>m;
m.func1();
m.func2();//报错
}
int main()
{
test01;
}
学习目标:
#include<iostream>
using namespace std;
//类模板对象做函数参数
template<class T1,class T2>
class Person
{
public:
Person(T1 name, T2 age)
{
this->m_Age = age;
this->m_Name = name;
}
void showPerson()
{
cout << "姓名:" << this->m_Name << "年龄:" << this->m_Age << endl;
}
T1 m_Name;
T2 m_Age;
};
//指定传入类型
void printPerson1(Person<string,int>& p)
{
p.showPerson();
}
void test01()
{
Person<string, int>p("孙悟空", 100);
printPerson1(p);
}
//参数模板化
template<class T1,class T2>
void printPerson2(Person<T1, T2>& p)
{
p.showPerson();
cout << "T1的类型为:" << typeid(T1).name() << endl;
cout << "T2的类型为:" << typeid(T2).name() << endl;
}
void test02()
{
Person<string, int>p("猪八戒", 90);
printPerson2(p);
}
template<class T>
void printPerson3(T& p)
{
p.showPerson();
//T的数据类型
cout << "T的数据类型;" << typeid(T).name() << endl;
}
//整个类都模板化
void test03()
{
Person<string, int>p("唐僧", 30);
printPerson3(p);
}
int main()
{
//test01();
//test02();
test03();
/*
姓名:唐僧年龄:30
T的数据类型;class Person<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int>
*/
}
总结:
最常用的还是第一种直接指定传入类型
当类模板碰到继承时,需要注意一下几点:
#include<iostream>
using namespace std;
//类模板和继承
template<class T>
class Base
{
public:
Base()
{
cout << "T的数据类型为:" << typeid(T).name() << endl;
}
T m;
};
//class Son :public Base//错误,必须要知道父类中T的类型,才能继承给子类
//{
//
//};
//正确做法,但这样父类类型被固定了
class Son :public Base<int>
{
};
void test01()
{
Son s1;
}
//如果想灵活指定父类中T的类型,子类也需要变为类模板
template<class T1,class T2>
class Son2 :public Base<T2>
{
public:
Son2()
{
cout << "T1的类型为:" << typeid(T1).name() << endl;
cout << "T2的类型为:" << typeid(T2).name() << endl;
}
T1 obj;
};
void test02()
{
Son2<int, char>s2;
}
int main()
{
test02();
/*
T的数据类型为:char
T1的类型为:int
T2的类型为:char
*/
}
总结:如果父类时类模板,子类许哟啊指定出父类中T的数据类型
学习目标:能够掌握类模板中成员函数类外实现
实例:
template <class T1,class T2>
class Person
{
public:
Person(T1 name,T2 name)
// {
// this->m_Name = name;
// this->m_Age = age;
// }
void showPerson()
// {
// cout<<"姓名:"<<this->m_Name<<"年龄"<<this->m_Age<<endl;
// }
T1 m_Name;
T2 m_Age;
}
//构造函数类外实现
template<class T1,class T2>
Person<T1 ,T2>::Person(T1 name,T2 age);
{
this->m_Name = name;
this->m_Age = age;
}
//成员函数类外实现
template<class T1,class T2>
void Person<T1,T2>::showPerson();
{
cout<<"姓名:"<<this->m_Name<<"年龄"<<this->m_Age<<endl;
}
void test01()
{
Person<string,int>P("Tom",20);
P.showPerson();
}
int main()
{
test01();
}
总结:类模板中成员函数类外实现时,需要加上模板参数列表
学习目标:
#pragma once
#include<iostream>
using namespace std;
template<class T1, class T2>
class Person
{
public:
Person(T1 name, T2 age);
void showPerson();
T1 m_Name;
T2 m_Age;
};
Person.cpp
#include"Person.h"
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
this->m_Age = age;
this->m_Name = name;
}
template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
cout << "姓名:" << this->m_Name << "年龄" << this->m_Age << endl;
}
源.cpp
#include<iostream>
using namespace std;
#include"Person.cpp"
//类模板的分文件编写和解决
void test01()
{
Person<string, int>p("Jerry", 18);
p.showPerson();
}
int main()
{
test01();
}
//注意直接包含include"Person.h"会报错,2个无法解析的外部命令,也就是指的test01里面
//的两个命令,此时只需要将include"Person.h"变为"Person.cpp"就可以。
#pragma once
#include<iostream>
using namespace std;
template<class T1, class T2>
class Person
{
public:
Person(T1 name, T2 age);
void showPerson();
T1 m_Name;
T2 m_Age;
};
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
this->m_Age = age;
this->m_Name = name;
}
template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
cout << "姓名:" << this->m_Name << "年龄" << this->m_Age << endl;
}
源.cpp中的代码
#include<iostream>
using namespace std;
#include"Person.hpp"
//类模板的分文件编写和解决
void test01()
{
Person<string, int>p("Jerry", 18);
p.showPerson();
}
int main()
{
test01();
}
//注意直接包含include"Person.h"会报错,2个无法解析的外部命令,也就是指的test01里面
//的两个命令,此时只需要将include"Person.h"变为"Person.cpp"就可以。也可以将cpp里面的东西
//复制到h文件后面,重命名为hpp最后在源.cpp中直接包含hpp
总结:主流的方法是第二种,将类模板成员函数写到一起,并将后缀给名为.hpp
学习目标:
#include<iostream>
using namespace std;
//通过全局函数打印Person信息
template<class T1,class T2>
class Person
{
//全局函数类内实现
friend void printPerson(Person<T1, T2> p)
{
cout << "姓名:" << p.m_Name << "年龄:" << p.m_Age << endl;
}
public:
Person(T1 name, T2 age)
{
this->m_Age = age;
this->m_Name = name;
}
private:
T1 m_Name;
T2 m_Age;
};
void test01()
{
Person<string, int>p("Tom", 20);
printPerson(p);
}
int main()
{
test01();
}
全局函数类外实现:需要提前让编译器知道全局函数的存在
实例:
#include<iostream>
using namespace std;
//提前让编译器知道Person类存在
template<class T1, class T2>
class Person;
//类外实现
template<class T1, class T2>
void printPerson2(Person<T1, T2>p)
{
cout << "姓名:" << p.m_Name << "年龄:" << p.m_Age << endl;
}
template<class T1,class T2>
class Person
{
//全局函数 类内实现
//friend void printPerson2(Person<T1, T2>p);//这样写是不行的,
//如果全局函数是类外实现,需要让编译器提前知道有这个函数存在。
friend void printPerson2<>(Person<T1, T2> p);
public:
Person(T1 name, T2 age)
{
this->m_Age = age;
this->m_Name = name;
}
private:
T1 m_Name;
T2 m_Age;
};
void test02()
{
Person<string, int>p("Jerry", 20);
printPerson2(p);
}
int main()
{
test02();
}
//类外实现会发生”无法解析的外部命令的错误“,因为声明的时候
//是按照普通函数声明的,但是实现的时候按照函数模板
//的方式来实现了,所以会发生错误。
总结:建议全局函数做类内实现,用法简单,而且编译器可以直接识别
案例描述:实现一个通用的数组类,要求如下:
#pragma once
#include<iostream>
using namespace std;
template<class T>
class MyArray
{
public:
//有参构造
MyArray(int capacity)
{
this->m_Capacity = capacity;
this->m_Size = 0;
this->pAddress = new T[this->m_Capacity];
cout << "MyArray的有参构造" << endl;
}
//拷贝构造函数
MyArray(const MyArray& arr)
{
cout << "MyArray的拷贝构造函数" << endl;
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
//this->pAddress = arr.pAddress;//浅拷贝,会导致堆区内存重复释放
this->pAddress = new T[arr.m_Capacity];
//将arr中的数据都拷贝过来
for (int i = 0; i < this->m_Size; i++)
{
this->pAddress[i] = arr.pAddress[i];
}
}
//operator=防止浅拷贝问题
MyArray& operator=(const MyArray& arr)
{
//先判断原来堆区是否有数据,如果有先释放
if (this->pAddress != NULL)
{
delete[] this->pAddress;
this->pAddress = NULL;
this->m_Capacity = 0;
this->m_Size = 0;
}
//深拷贝
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
this->pAddress = new T[arr.m_Capacity];
for (int i = 0; i < this->m_Size; i++)
{
this->pAddress[i] = arr.pAddress[i];
}
return *this;
}
//尾插法
void Push_Back(const T& val)
{
//判断容量是否已经等于大小
if (this->m_Capacity == this->m_Size)
{
return;
}
this->pAddress[this->m_Size] = val;
this->m_Size++;//更新数组大小
}
//尾删法
void Pop_Back()
{
//让用户访问不到最后一个元素,就是尾删,逻辑删除
if (this->m_Size == 0)
{
return;
}
this->m_Size--;
}
//让用户可以通过下标方式访问数组的元素,,重载[]运算符,另外作为左值访问
//arr[0] = 100,需要返回T的引用
T& operator[](int index)
{
return this->pAddress[index];
}
//返回数组容量
int getCapacity()
{
return this->m_Capacity;
}
int getSize()
{
return this->m_Size;
}
~MyArray()
{
cout << "MyArray析构函数" << endl;
//MyArray的析构函数
if (this->pAddress != NULL)
{
delete[] this->pAddress;
this->pAddress = NULL;
}
}
private:
T* pAddress;//指向堆区开辟的真实数组
int m_Capacity;//数组容量
int m_Size;//数组元素个数
};
源.cpp
#include"MyArray.hpp"
void printIntArray(MyArray<int>& arr)
{
for (int i = 0; i < arr.getSize(); i++)
{
cout << arr[i] << endl;
}
}
void test01()
{
MyArray<int> arr1(5);
for (int i = 0; i < 5; i++)
{
arr1.Push_Back(i);//利用尾插法向数组中插入数据
}
cout << "arr1的打印输出为:" << endl;
printIntArray(arr1);
cout << "arr1的容量为:"<<arr1.getCapacity() << endl;
cout << "arr1的大小为:"<<arr1.getSize() << endl;
MyArray<int>arr2(arr1);
cout << "arr2的打印输出为:" << endl;
printIntArray(arr2);
//尾删法
arr2.Pop_Back();
cout << "arr2尾删后:" << endl;
printIntArray(arr2);
cout << "arr2的容量为:" << arr2.getCapacity() << endl;
cout << "arr2的大小为:" << arr2.getSize() << endl;
//MyArray<int>arr2(arr1);
//MyArray<int>arr3(100);
//arr3 = arr1;
/*
输出
MyArray的有参构造
arr1的打印输出为:
0
1
2
3
4
arr1的容量为:5
arr1的大小为:5
MyArray的拷贝构造函数
arr2的打印输出为:
0
1
2
3
4
arr2尾删后:
0
1
2
3
arr2的容量为:5
arr2的大小为:4
MyArray析构函数
MyArray析构函数
*/
}
//测试自定义数据类型
class Person
{
public:
Person() {};
Person(string name, int age)
{
this->m_Age = age;
this->m_Name = name;
}
string m_Name;
int m_Age;;
};
void printPersonArray(MyArray<Person>& arr)
{
for (int i = 0; i < arr.getSize(); i++)
{
cout << "姓名:" << arr[i].m_Name << "年龄:" << arr[i].m_Age << endl;
}
}
void test02()
{
MyArray<Person>arr(10);
Person p1("孙悟空", 999);
Person p2("韩信", 10);
Person p3("李四", 150);
Person p4("张三", 103);
Person p5("王五", 107);
//尾插法插入
arr.Push_Back(p1);
arr.Push_Back(p2);
arr.Push_Back(p3);
arr.Push_Back(p4);
arr.Push_Back(p5);
//打印数组
printPersonArray(arr);
//输出容量
cout << "arr的容量为:"<<arr.getCapacity() << endl;
//输出大小
cout << "arr的大小为:" << arr.getSize() << endl;
/*
MyArray的有参构造
姓名:孙悟空年龄:999
姓名:韩信年龄:10
姓名:李四年龄:150
姓名:张三年龄:103
姓名:王五年龄:107
arr的容量为:10
arr的大小为:5
MyArray析构函数
*/
}
int main()
{
//test01();
test02();
}
STL大体分为六大组件:分别是:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器
容器:置物之所也
STL容器就是将运用最广泛的一些数据结构实现出来
常用的数据结构:数组,链表,树,栈,队列,集合,映射表等
这些容器分为序列式容器和关联式容器两种;
序列式容器:强调值的排序,序列式容器中的每个元素都有固定的位置
关联式容器:二叉树结构,个元素之间没有严格的物理上的顺序关系
算法:问题之解法也
有限的步骤,解决逻辑或数学上的问题,这一门学科我们叫算法(Algorithms)
算法分为:质变算法和非质变算法。
质变算法:是指运算过程中会更改区间内的元素的内容。例如拷贝,替换,删除等
非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找,计数,遍历,寻找极值等
迭代器:容器和算法之间的粘合剂
提供一种方法,是指能够依序寻访某个容器所含的各个元素,而又无需暴露该容器内部表示方式。
每个容器都有自己专属的迭代器
迭代器使用非常类似于指针,初学阶段我们可以先理解迭代器为指针
迭代器种类:
常用的容器中迭代器为双向迭代器和随机访问迭代器
了解STL中容器,算法,迭代器概念之后,我们利用代码感受STL的魅力
STL中最常用的容器为Vector,可以理解为数组,下面学习如何向容器中插入数据,并遍历这个容器
容器:vector
算法:for_each
迭代器:vector
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
//vector容器存放内置数据类型
void myPrint(int val)
{
cout << val << endl;
}
void test01()
{
//创建vector的容器
vector<int>v;
//向容器中插入数据
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
//通过迭代器访问容器中的数据
//vector<int>::iterator itBegin = v.begin();//起始迭代器,指向容器中第一个元素
//vector<int>::iterator itEnd = v.end();//结束迭代器 指向容器中最后一个元素的下一个位置
////第一种遍历方式
//while (itBegin != itEnd)
//{
// cout << *itBegin << endl;
// itBegin++;
//}
//第二种遍历方式
//for (vector<int>::iterator it = v.begin(); it != v.end() ; it++)
//{
// cout << *it << endl;
//}
//第三种调用方式。利用STL提供遍历算法
for_each(v.begin(), v.end(), myPrint);
}
int main()
{
test01();
}
学习目标:vector中存放自定义数据类型,并打印输出
实例:
#include<iostream>
#include<vector>
using namespace std;
//vector容器中存放自定义数据类型
class Person
{
public:
Person(string name, int age)
{
this->m_Age = age;
this->m_Name = name;
}
string m_Name;
int m_Age;
};
void test01()
{
vector<Person>v;
Person p1("aaa", 10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);
Person p5("eee", 50);
//向容器中添加数据
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
//遍历容器中的数据
for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
{
//两种方法都行
cout << "姓名:" << it->m_Name<<"\t" << "年龄:" << it->m_Age << endl;
cout << "姓名:" << (*it).m_Name<<"\t" << "年龄:" << (*it).m_Age << endl;
}
}
void test02()
{
vector<Person*>v;
Person p1("aaa", 10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);
Person p5("eee", 50);
//向容器中添加数据
v.push_back(&p1);
v.push_back(&p2);
v.push_back(&p3);
v.push_back(&p4);
v.push_back(&p5);
//遍历容器
for (vector<Person*>::iterator it = v.begin();it != v.end();it++)
{
//这里有个技巧(*it)的类型就是尖括号里面的数据类型,就是Person*
cout << "姓名:" << (*it)->m_Name << "年龄:" << (*it)->m_Age << endl;
}
}
int main()
{
//test01();
test02();
}
小技巧:*it的数据类型就是vector<>中尖括号的数据类型
学习目标:容器中嵌套容器,我们将所有数据进行遍历输出
实例:
#include<iostream>
#include<vector>
using namespace std;
//容器嵌套容器
void test01()
{
vector<vector<int>>v;
//创建小容器
vector<int>v1;
vector<int>v2;
vector<int>v3;
vector<int>v4;
//向小容器添加数据
for (int i = 0; i < 4; i++)
{
v1.push_back(i + 1);
v2.push_back(i + 2);
v3.push_back(i + 3);
v4.push_back(i + 4);
}
//将小容器添加到大容器中
v.push_back(v1);
v.push_back(v2);
v.push_back(v3);
v.push_back(v4);
//通过大容器遍历所有的数据
for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++)
{
//(*it)---vector<int>
for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
{
cout << *vit << " ";
}
cout << endl;
}
}
int main()
{
test01();
}
本质:
构造函数原型:
#include<iostream>
#include<string>
using namespace std;
//string构造函数
void test01()
{
string s1;//默认构造
const char* str = "hello world";
string s2(str);
cout << "s2=" << s2 << endl;
string s3(s2);
cout << "s3=" << s3 << endl;
string s4(10, 'a');
cout << "s4=" << s4 << endl;
}
int main()
{
test01();
/*
s2=hello world
s3=hello world
s4=aaaaaaaaaa
*/
}
功能描述:
#include<iostream>
using namespace std;
void test01()
{
string str1;
str1 = "hello world";
cout << "str1=" << str1 << endl;
string str2;
str2 = str1;
cout << "str2=" << str2 << endl;
string str3;
str3 = 'a';
cout << "str3=" << str3 << endl;
string str4;
str4.assign("hello world2");
cout << "str4=" << str4 << endl;
string str5;
str5.assign("hello C++", 5);
cout << "str5=" << str5 << endl;
string str6;
str6.assign(str5);
cout << "str6=" << str6 << endl;
string str7;
str7.assign(6, 'd');
cout << "str7=" << str7 << endl;
}
int main()
{
test01();
}
/*
str1=hello world
str2=hello world
str3=a
str4=hello world2
str5=hello
str6=hello
str7=dddddd
*/
功能描述:
#include<iostream>
using namespace std;
void test01()
{
string str1 = "我";
str1 += "爱玩游戏";
cout << "str1=" << str1 << endl;
str1 += ';';
cout << "str1=" << str1 << endl;
string str2 = "LoL DnF";
str1 = str1 + str2;
cout << "str1=" << str1 << endl;
string str3 = "I";
str3.append("love");
cout << "str3=" << str3 << endl;
str3.append("game abcd", 4);
cout << "str3=" << str3 << endl;
str3.append(str2);
cout << "str3=" << str3 << endl;
str3.append(str2, 0, 3);//只截取LOL
cout << "str3=" << str3 << endl;
str3.append(str2, 4, 3);//只截取DNF
cout << "str3=" << str3 << endl;
}
int main()
{
test01();
}
字符串重载版本很多,初学者记住几个就可以
功能描述:
#include<iostream>
using namespace std;
//字符查找和替换
//查找
void test01()
{
string str1 = "abcdefgde";
int pos = str1.find("de");
cout << "pos=" << pos << endl;//如果查到了,返回索引,否则返回-1
if (pos!=-1)
{
cout << "找到了字符串,pos=" << pos << endl;
}
else
{
cout << "未找到字符串" << endl;
}
//rfind和find的区别,
//rfind是从右往左查找,而find从左往右查找。返回的值都一样。
pos = str1.rfind("de");
cout << "pos=" << pos << endl;//
}
//替换
void test02()
{
string str1 = "abcdefg";
str1.replace(1, 3, "1111");
cout << "str1=" << str1 << endl;
//输出:str1=a1111efg
}
int main()
{
//test01();
test02();
}
功能描述:
#include<iostream>
using namespace std;
//字符串比较
void test01()
{
string str1 = "hello";
string str2 = "jello";
if (str1.compare(str2) ==0)
{
cout << "str1等于str2" << endl;
}
else if (str1.compare(str2)>0)
{
cout << "str1大于str2" << endl;
}
else
{
cout << "str1小于str2" << endl;
}
}
int main()
{
test01();
}
对比方式是按照Ascii码逐个比较
string中单个字符存取方式有两种
#include<iostream>
using namespace std;
//string 字符获取
void test01()
{
string str = "hello";
cout << "str=" << str << endl;
//通过[]访问单个字符
for (int i = 0; i < str.size(); i++)
{
cout << str[i] << endl;
}
//通过at方法访问单个字符
for (int i = 0; i < str.size(); i++)
{
cout << str.at(i) << " ";
}
cout << endl;
//修改单个字符
str[0] = 'x';
cout << "str = " << str << endl;
str.at(1) = 'x';
cout << "str = " << str << endl;
}
int main()
{
test01();
}
功能描述:
#include<iostream>
using namespace std;
//字符串插入和删除
void test01()
{
string str = "hello";
//插入
str.insert(1, "111");
//hello
cout << "str=" << str << endl;//str=h111ello
//删除
str.erase(1, 3);
cout << "str=" << str << endl;//str=hello
}
int main()
{
test01();
}
功能描述:
#include<iostream>
using namespace std;
//string 求字串
void test01()
{
string str = "dfaga";
string subStr = str.substr(1, 3);
cout << "subStr = " << subStr << endl;//fag
}
//使用操作
void test02()
{
string email = "zhagnsan@sina.com";
//从邮件地址获取用户名信息
int pos = email.find("@");
string userName = email.substr(0, pos);
cout << "用户名:" << userName << endl;//用户名:zhagnsan
}
int main()
{
//test01();
test02();
}
总结:灵活运用求字串功能,可以在实际开发中获取有效的信息
功能:
功能描述:
#include<iostream>
using namespace std;
#include<vector>
//vector容器构造
void printVector(vector<int>& v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << (*it) << " ";
}
cout << endl;
}
void test01()
{
vector<int>v1;//默认构造无参构造
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);//0 1 2 3 4 5 6 7 8 9
//通过区间方式构造
vector<int>v2(v1.begin(), v1.end());
printVector(v2);//0 1 2 3 4 5 6 7 8 9
//n个elem方式构造
vector<int>v3(10, 100);
printVector(v3);//100 100 100 100 100 100 100 100 100 100
//拷贝构造
vector<int>v4(v3);
printVector(v4);//100 100 100 100 100 100 100 100 100 100
}
int main()
{
test01();
}
功能描述:
#include<iostream>
#include<vector>
using namespace std;
//vector赋值
void printVector(vector<int>& v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << (*it) << " ";
}
cout << endl;
}
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
//赋值operator=
vector<int>v2;
v2 = v1;
printVector(v2);
//assign
vector<int>v3;
v3.assign(v1.begin(), v1.end());
printVector(v3);
//n个elem方式赋值
vector<int>v4;
v4.assign(10, 100);
printVector(v4);
/*
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
100 100 100 100 100 100 100 100 100 100
*/
}
int main()
{
test01();
总结:vector赋值方式比较简单,使用operator或者assign都可以
功能描述:
#include<iostream>
using namespace std;
#include<vector>
//vector容器的容量和大小操作
void printVector(vector<int>& v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << (*it) << " ";
}
cout << endl;
}
void test01()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
if (v1.empty())//为真,代表容器为空
{
cout << "v1为空" << endl;
}
else
{
cout << "v1不为空" << endl;
cout << "v1的容量为:" << v1.capacity() << endl;
}
}
int main()
{
test01();
}
#include<iostream>
using namespace std;
#include<vector>
//vector容器的容量和大小操作
void printVector(vector<int>& v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << (*it) << " ";
}
cout << endl;
}
void test01()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
if (v1.empty())//为真,代表容器为空
{
cout << "v1为空" << endl;
}
else
{
cout << "v1不为空" << endl;
cout << "v1的容量为:" << v1.capacity() << endl;
cout << "v1的大小为:" << v1.size() << endl;
/*
0 1 2 3 4 5 6 7 8 9
v1不为空
v1的容量为:13
v1的大小为:10
*/
//容量永远大于等于大小
//注意,容量为13而不是10,这是他内部算法决定的,动态扩展机制。
}
//重新制定大小
v1.resize(15);
//如果重新制定的比原来的长,默认用0来填充新位置
printVector(v1);//0 1 2 3 4 5 6 7 8 9 0 0 0 0 0
v1.resize(20, 100);//利用重载版本可以指定默认填充值,参数2
printVector(v1);//0 1 2 3 4 5 6 7 8 9 0 0 0 0 0 100 100 100 100 100
//重新指定的比原来短,超出部分被删掉
v1.resize(5);
printVector(v1);//0 1 2 3 4
}
int main()
{
test01();
}
功能描述:
#include<iostream>
using namespace std;
#include<vector>
void printVector(vector<int>& v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << (*it) << " ";
}
cout << endl;
}
void test01()
{
vector<int>v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
printVector(v1);//10 20 30
//尾删
v1.pop_back();
printVector(v1);//10 20
//插入
v1.insert(v1.begin(), 100);
printVector(v1);//100 10 20
v1.insert(v1.begin(), 2, 1000);
printVector(v1);//1000 1000 100 10 20
//删除,参数也是迭代器
v1.erase(v1.begin());
printVector(v1);// 1000 100 10 20
v1.erase(v1.begin(), v1.end());
printVector(v1);//空容器,类似于清空,类似于v1.clear()
}
int main()
{
test01();
}
功能描述:
#include<iostream>
using namespace std;
#include<vector>
//vector容器,数据存取
void test01()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
//利用[]方式访问数组中元素
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
//利用at方式访问元素
for (int i = 0; i < v1.size(); i++)
{
cout << v1.at(i) << " ";
}
cout << endl;
//获取第一个和最后一个元素
cout << "第一个元素为:" << v1.front() << endl;
//获取最后一个元素
cout << "最后一个元素为:" << v1.back() << endl;
/*
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
第一个元素为:0
最后一个元素为:9
*/
}
int main()
{
test01();
}
功能描述:
#include<iostream>
using namespace std;
#include<vector>
//vector容器互换
void printVector(vector<int>& v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << (*it) << " ";
}
cout << endl;
}
//基本使用
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
cout << "交换前的打印" << endl;
printVector(v1);
vector<int> v2;
for (int i = 10; i > 0; i--)
{
v2.push_back(i);
}
printVector(v2);
cout << "交换后的打印" << endl;
v1.swap(v2);
printVector(v1);
printVector(v2);
/*
交换前的打印
0 1 2 3 4 5 6 7 8 9
10 9 8 7 6 5 4 3 2 1
交换后的打印
10 9 8 7 6 5 4 3 2 1
0 1 2 3 4 5 6 7 8 9
*/
}
//实际用途
//巧用swap可以收缩内存空间
void test02()
{
vector<int> v;
for (int i = 0; i < 100000; i++)
{
v.push_back(i);
}
cout << "v的容量为:" << v.capacity() << endl;
cout << "v的大小为:" << v.size() << endl;
//v的容量为:138255
//v的大小为:100000
v.resize(3);//重新指定大小
cout << "v的容量为:" << v.capacity() << endl;
cout << "v的大小为:" << v.size() << endl;
//v的容量为:138255
//v的大小为:3
//这里可以看出容量大大浪费了,容量远大于大小
//可以巧用swap收缩内存
vector<int>(v).swap(v);//vector<int>(v)是匿名对象
//刚才是调用拷贝构造函数创建匿名对象,会按v目前所用元素个数(3)来初始化匿名对象大小。
//.swap(v)是做了容器的交换。匿名对象指向大的空间但是会被系统回收。
cout << "v的容量为:" << v.capacity() << endl;
cout << "v的大小为:" << v.size() << endl;
//v的容量为:3
//v的大小为:3
}
int main()
{
//test01();
test02();
}
功能描述:
#include<iostream>
#include<vector>
using namespace std;
//vector容器 预留空间
void test01()
{
vector<int> v;
//利用reserve预留空间
v.reserve(100000);
int num = 0;//统计开辟次数
int* p = NULL;
for (int i = 0; i < 100000; i++)
{
v.push_back(i);
if (p != &v[0])
{
p = &v[0];
num++;
}
}
cout << "num = " << num << endl;
//num = 30,一共开辟了30次内存。
//使用reserve之后,num = 1,只开辟了一次
}
int main()
{
test01();
}
功能:
功能描述:
#include<iostream>
using namespace std;
#include<deque>
//deque构造函数
void printDeque(const deque<int>& d)//如果限制只读状态,则迭代器也需要变
{
for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
deque<int>d1;
for (int i = 0; i < 10; i++)
{
d1.push_back(i);
}
printDeque(d1);
deque<int>d2(d1.begin(), d1.end());
printDeque(d2);
deque<int>d3(10, 100);
printDeque(d3);
deque<int>d4(d3);
printDeque(d4);
/*
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
*/
}
int main()
{
test01();
}
功能描述:
#include<iostream>
using namespace std;
#include<deque>
//deque容器打印
void printDeque(const deque<int>& d)
{
for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//deque容器赋值操作
void test01()
{
deque<int>d1;
for (int i = 0; i < 10; i++)
{
d1.push_back(i);
}
printDeque(d1);
//=赋值操作
deque<int>d2;
d2 = d1;
printDeque(d2);
//assign赋值操作
deque<int>d3;
d3.assign(d1.begin(), d1.end());
printDeque(d3);
deque<int>d4;
d4.assign(10, 100);
printDeque(d4);
}
功能描述:
#include<iostream>
#include<deque>
using namespace std;
void printDeque(const deque<int>& d)
{
for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//deque容器大小操作
void test01()
{
deque<int> d1;
for (int i = 0; i < 10; i++)
{
d1.push_back(i);
}
if (d1.empty())
{
cout << "d1为空" << endl;
}
else
{
cout << "d1不为空" << endl;
cout << "d1的大小为:" << d1.size() << endl;
//deque容器没有容量概念
}
//重新指定大小
d1.resize(15);//用0来填充
printDeque(d1);
d1.resize(15, 1);//用1来填充
d1.resize(5);
}
int main()
{
test01();
}
#include<iostream>
#include<deque>
using namespace std;
void printDeque(const deque<int>& d)
{
for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//deque容器大小操作
void test01()
{
deque<int> d1;
for (int i = 0; i < 10; i++)
{
d1.push_back(i);
}
if (d1.empty())
{
cout << "d1为空" << endl;
}
else
{
cout << "d1不为空" << endl;
cout << "d1的大小为:" << d1.size() << endl;
//deque容器没有容量概念
}
//重新指定大小
d1.resize(15);//用0来填充
printDeque(d1);
d1.resize(15, 1);//用1来填充
printDeque(d1);
d1.resize(5);
printDeque(d1);
/*
d1不为空
d1的大小为:10
0 1 2 3 4 5 6 7 8 9 0 0 0 0 0
0 1 2 3 4 5 6 7 8 9 0 0 0 0 0
0 1 2 3 4
*/
}
int main()
{
test01();
}
功能描述:
void test02()
{
deque<int>d1;
d1.push_back(10);
d1.push_back(20);
d1.push_front(100);
d1.push_front(200);
printDeque(d1);
//200 100 10 20
//insert插入
d1.insert(d1.begin(), 1000);
printDeque(d1);
d1.insert(d1.begin(), 2, 10000);
//按照区间插入
deque<int>d2;
d2.push_back(1);
d2.push_back(2);
d2.push_back(3);
d1.insert(d1.begin(), d2.begin(), d2.end());//d1.begin的位置插入d2.begin()daoo d2.end的区间
}
void test03()
{
deque<int>d1;
d1.push_back(10);
d1.push_back(20);
d1.push_front(100);
d1.push_front(200);
//删除
deque<int>::iterator it = d1.begin();
it++;
d1.erase(it);
printDeque(d1);//200 10 20
//按照区间方式删除
d1.erase(d1.begin(), d1.end());//相当于d1.clear();
printDeque(d1);
}
int main()
{
test03();
}
总结:
功能描述
#include<iostream>
using namespace std;
#include<deque>
//deque容器数据存取
void test01()
{
deque<int> d;
d.push_back(10);
d.push_back(20);
d.push_back(30);
d.push_front(100);
d.push_front(200);
d.push_front(300);
//通过[]方式访问元素
for (int i = 0; i < d.size(); i++)
{
cout << d[i] << " ";
}
cout << endl;
//通过at方式访问
for (int i = 0; i < d.size(); i++)
{
cout << d.at(i) << " ";
}
cout << endl;
cout << "第一个元素" << d.front() << endl;
cout << "最后一个元素" << d.back() << endl;
/*
300 200 100 10 20 30
300 200 100 10 20 30
第一个元素300
最后一个元素30
*/
}
int main()
{
test01();
}
功能描述:
#include<iostream>
#include<deque>
#include<algorithm>
using namespace std;
void printDeque(const deque<int> d)
{
for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//deque容器排序
void test01()
{
deque<int>d;
d.push_back(10);
d.push_back(20);
d.push_back(30);
d.push_front(13);
d.push_front(26);
d.push_front(17);
cout << "排序前" << endl;
printDeque(d);
//排序操作,默认升序
//对于支持随机访问的迭代器都可以利用sort算法对其进行排序,vector也可以。
sort(d.begin(), d.end());
cout << "排序后" << endl;
printDeque(d);
}
int main()
{
test01();
}
有5名选手,选手ABCDE,10个评委分别对每一名选手打分,去除最高分,去除评委中最低分,取平均分。
#include<iostream>
#include<ctime>
#include<algorithm>
using namespace std;
#include<vector>
#include<deque>
//选手类
class Person
{
public:
Person(string name,int score)
{
this->m_Name = name;
this->m_Score = score;
}
string m_Name;
int m_Score;//平均分
};
void createPerson(vector<Person>& v)
{
string nameSeed = "ABCDE";
for (int i = 0; i < 5; i++)
{
string name = "选手";
name += nameSeed[i];
int score = 0;
Person p(name, score);
//将创建的Person对象放入容器中
v.push_back(p);
}
}
void setScore(vector<Person>& v)
{
for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
{
deque<int>d;
for (int i = 0; i < 10; i++)
{
int score = rand() % 41 + 60;//60~100
d.push_back(score);
}
//cout << "选手:" << it->m_Name << "打分" << endl;
//for (deque<int>::iterator dit = d.begin(); dit != d.end(); dit++)
//{
// cout << *dit << " ";
//}
cout << endl;
//排序
sort(d.begin(), d.end());
//去除最高分和最低分
d.pop_back();
d.pop_front();
//取平均分
int sum = 0;
for (deque<int>::iterator dit = d.begin(); dit != d.end(); dit++)
{
sum += *dit;//累加
}
int avg = sum / d.size();
//将平均分赋给选手
(*it).m_Score = avg;
}
}
void showScore(vector<Person>& v)
{
for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
{
cout << "姓名:" << it->m_Name << "平均分:" << it->m_Score << endl;
}
}
int main()
{
//随机数种子
srand((unsigned int)time(NULL));
//创建5名选手
vector<Person> v;//存放选手容器
createPerson(v);
//测试
for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
{
cout << "姓名:" << (*it).m_Name << "得分:" << (*it).m_Score << endl;
}
//给5名选手打分
setScore(v);
//显示最后打分
showScore(v);
}
/*
姓名:选手A得分:0
姓名:选手B得分:0
姓名:选手C得分:0
姓名:选手D得分:0
姓名:选手E得分:0
姓名:选手A平均分:81
姓名:选手B平均分:79
姓名:选手C平均分:79
姓名:选手D平均分:82
姓名:选手E平均分:80
*/
概念:stack是一种先进后出(first in last out filo)的数据结构,她只有一个出口
栈中只有顶栈的元素才可以被外界使用,因此栈不允许有遍历行为
功能描述:栈容器常用的对外接口
构造函数:
#include<iostream>
#include<stack>
using namespace std;
//栈stack容器
void test01()
{
//特点:符合先进后出的数据结构
stack<int>s;
//入栈
s.push(10);
s.push(20);
s.push(30);
s.push(40);
//只要栈不为空,查看栈顶,并且执行出栈操作
while (!s.empty())
{
//查看栈顶元素
cout << "栈顶元素:" << s.top() << endl;
//出栈
s.pop();
}
cout << "栈的大小:" << s.size() << endl;
}
/*
栈顶元素:40
栈顶元素:30
栈顶元素:20
栈顶元素:10
栈的大小:0
*/
int main()
{
test01();
}
概念:Queue是一种先进先出(first in first out,fifo)的数据结构,他有两个出口
队列容器允许从一端新增元素,从另一端移除元素
队列中只有队头和队尾才可以被外界使用,因此队列不允许有遍历行为
队列中进数据称为--入队 push
队列中出数据称为--出队 pop
生活中的队列:排队
功能描述:栈容器常用的对外接口 构造函数:
#include<iostream>
using namespace std;
#include<queue>
class Person
{
public:
Person(string name, int age)
{
this->m_Age = age;
this->m_Name = name;
}
string m_Name;
int m_Age;
};
//队列
void test01()
{
//创建队列
queue<Person>q;
//准备数据
Person p1("唐僧", 30);
Person p2("孙悟空", 22);
Person p3("猪八戒", 13);
Person p4("沙僧", 75);
//入队
q.push(p1);
q.push(p2);
q.push(p3);
q.push(p4);
//判断只要队列不为空,查看对头,查看队尾,出队
while (!q.empty())
{
//查看对头
cout << "队头元素---姓名:" << q.front().m_Name << "年龄:" << q.front().m_Age << endl;
//查看队尾
cout << "队尾元素---姓名:" << q.back().m_Name << "年龄:" << q.back().m_Age << endl;
//出队
q.pop();
}
cout << "队列的大小为:" << q.size() << endl;
}
int main()
{
test01();
}
/*
队头元素---姓名:唐僧年龄:30
队尾元素---姓名:沙僧年龄:75
队头元素---姓名:孙悟空年龄:22
队尾元素---姓名:沙僧年龄:75
队头元素---姓名:猪八戒年龄:13
队尾元素---姓名:沙僧年龄:75
队头元素---姓名:沙僧年龄:75
队尾元素---姓名:沙僧年龄:75
队列的大小为:0
*/
功能:将数据进行链式存储
链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的
链表的组成:一个是存储数据元素的数据域,另一个是存储下一个节点地址的指针域
STL中的链表是一个双向循环链表
优点:可以对任意位置进行快速插入删除元素
缺点:容器遍历速度没有数组快,占用的空间比数组大
由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器
list的优点:
功能描述:
#include<iostream>
using namespace std;
#include<list>
//list容器构造函数
void printListArray(const list<int>& lst)
{
for (list<int>::const_iterator it = lst.begin(); it != lst.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
//创建list容器
list<int>L1;//默认构造函数
//添加元素
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
//遍历容器
printListArray(L1);
//区间方式构造
list<int>L2(L1.begin(), L1.end());
printListArray(L2);
//拷贝构造
list<int>L3(L2);
printListArray(L3);
//n个elem
list<int>L4(10, 1000);
printListArray(L4);
}
int main()
{
test01();
}
/*
10 20 30 40
10 20 30 40
10 20 30 40
1000 1000 1000 1000 1000 1000 1000 1000 1000 1000
*/
list构造方式同其他几个STL常用容器一样
功能描述:
#include<iostream>
using namespace std;
#include<list>
//赋值
void printList(const list<int>& L)
{
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
{
cout << *it << endl;
}
}
void test01()
{
list<int>L1;
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
list<int>L2;
L2 = L1;//operator=赋值
printList(L2);
list<int>L3;
L3.assign(L2.begin(), L2.end());
printList(L3);
list<int>L4;
L4.assign(10, 100);
printList(L4);
}
void test02()
{
list<int>L1;
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
list<int>L2;
L2.assign(10, 100);
cout << "交换前:" << endl;
printList(L1);
printList(L2);
cout << endl;
L1.swap(L2);
cout << "交换后:" << endl;
printList(L1);
printList(L2);
}
int main()
{
test02();
/*
交换前:
10
20
30
40
100
100
100
100
100
100
100
100
100
100
交换后:
100
100
100
100
100
100
100
100
100
100
10
20
30
40
*/
}
功能描述:
#include<iostream>
using namespace std;
#include<list>
//list容器大小操作
void printList(const list<int>& L)
{
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
list<int>L1;
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
printList(L1);
//判断容器是否为空
if (L1.empty())
{
cout << "L1为空" << endl;
}
else
{
cout << "L1不为空" << endl;
cout << "L1的元素个数为:" << L1.size() << endl;
}
//重新制定大小
L1.resize(10,10000);
printList(L1);
L1.resize(2);
printList(L1);
}
int main()
{
test01();
}
/*
10 20 30 40
L1不为空
L1的元素个数为:4
10 20 30 40 10000 10000 10000 10000 10000 10000
10 20
*/
功能描述:
功能描述:
功能描述:
bool myCompare(int v1,int v2)
{
//降序,就让第一个数>第二个数
return v1>v2;
}
//然后直接在sort里面传入这个函数
L1.sort(myCompare)
案例描述:将Person自定义数据类型进行排序,Person中属性有姓名、年龄、身高
排序规则:按照年龄进行升序,如果年龄现同按照身高进行降序
实例:
#include<iostream>
using namespace std;
#include<string>
#include<list>
//list容器 排序案例 对于自定义数据类型做排序
//按照年龄进行升序,如果年龄相同按照身高进行排序
class Person
{
public:
Person(string name, int age, int height)
{
this->m_Name = name;
this->m_Age = age;
this->m_Height = height;
}
string m_Name;
int m_Age;
int m_Height;
};
//指定排序规则
bool comparePerson(Person&p1,Person &p2)
{
//按照年龄做一个升序
if (p1.m_Age == p2.m_Age)
{
//年龄相同,按照身高降序
return p1.m_Height > p2.m_Height;
}
return p1.m_Age < p2.m_Age;
}
void test01()
{
list<Person> L;//创建容器
//准备数据
Person p1("刘备", 35, 175);
Person p2("曹操", 35, 199);
Person p3("孙权", 80, 180);
Person p4("赵云", 89, 156);
Person p5("张飞", 35, 180);
Person p6("关羽", 17, 230);
//插入数据
L.push_back(p1);
L.push_back(p2);
L.push_back(p3);
L.push_back(p4);
L.push_back(p5);
L.push_back(p6);
for (list<Person>::iterator it = L.begin(); it != L.end(); it++)
{
cout << "姓名:" << (*it).m_Name << "年龄:" << it->m_Age << "身高:" << it->m_Height << endl;
}
//排序
cout << "----------------------" << endl;
cout << "排序后:" << endl;
L.sort(comparePerson);
for (list<Person>::iterator it = L.begin(); it != L.end(); it++)
{
cout << "姓名:" << (*it).m_Name << "年龄:" << it->m_Age << "身高:" << it->m_Height << endl;
}
}
/*
姓名:刘备年龄:35身高:175
姓名:曹操年龄:35身高:199
姓名:孙权年龄:80身高:180
姓名:赵云年龄:89身高:156
姓名:张飞年龄:35身高:180
姓名:关羽年龄:17身高:230
----------------------
排序后:
姓名:关羽年龄:17身高:230
姓名:曹操年龄:35身高:199
姓名:张飞年龄:35身高:180
姓名:刘备年龄:35身高:175
姓名:孙权年龄:80身高:180
姓名:赵云年龄:89身高:156
*/
int main()
{
test01();
}
简介:
功能描述:创建set容器以及赋值
构造:
#include<iostream>
#include<set>
using namespace std;
//set容器构造和赋值
void printSet(set<int>& s)
{
for (set<int>::iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
set<int>s1;
s1.insert(10);//插入数据只有insert方式
s1.insert(40);
s1.insert(30);
s1.insert(20);
s1.insert(40);
//遍历容器
printSet(s1);
//set容器的特点:所有元素插入的时候自动排序,
//set容器不允许插入重复的值
//拷贝构造
set<int>s2(s1);
printSet(s2);
}
int main()
{
test01();
}
功能描述:
功能描述:
功能描述:
set<int>::iterator pos = s1.find(30);
if(pos != s1.end())
{
cout<<"找到元素"<<*pos<<endl;
}
else
{
cout<<"未找到元素:"<<endl;
}
//统计30的个数
int num = s1.count(30);
//对于set而言,统计结果,要么是0要么是1
cout<<"num="<<num<<endl;
总结:
学习目标:
功能描述:
#include<iostream>
using namespace std;
#include<string>
void test01()
{
//第一种方式
pair<string, int>p("Tom", 20);
cout << "姓名:" << p.first << "年龄:" << p.second << endl;
//第二种方式
pair<string, int>p2 = make_pair("Jerry", 20);
cout << "姓名:" << p2.first << "年龄:" << p.second << endl;
}
int main()
{
test01();
/*
姓名:Tom年龄:20
姓名:Jerry年龄:20
*/
}
学习目标:
#include<iostream>
using namespace std;
#include<string>
#include<set>
//set容器排序
//仿函数
class MyCompare
{
public:
bool operator()( int v1, int v2)const//()代表重载的符号()
{
return v1 > v2;
}
};
void test01()
{
set<int>s1;
s1.insert(10);
s1.insert(40);
s1.insert(20);
s1.insert(30);
s1.insert(50);
for (set<int>::iterator it = s1.begin(); it != s1.end(); it++)
{
cout << *it << " ";
}
cout << endl;
//指定排序规则从大到小
set<int,MyCompare>s2;
s2.insert(10);
s2.insert(40);
s2.insert(20);
s2.insert(30);
s2.insert(50);
for (set<int,MyCompare>::iterator it = s2.begin(); it != s2.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
/*
10 20 30 40 50
50 40 30 20 10
*/
int main()
{
test01();
}
实例二:set存放自定义数据类型
#include<iostream>
using namespace std;
#include<set>
//set容器排序,存放自定义数据类型
class Person
{
public:
Person(string name, int age)
{
this->m_Age = age;
this->m_Name = name;
}
string m_Name;
int m_Age;
};
class myCompare
{
public:
bool operator()(const Person& p1, const Person& p2)const
{
//按照年龄降序
return p1.m_Age > p2.m_Age;
}
};
void test01()
{
set<Person,myCompare>s;
//创建Person对象
Person p1("刘备", 24);
Person p2("关羽", 23);
Person p3("张飞", 22);
Person p4("赵云", 21);
s.insert(p1);
s.insert(p2);
s.insert(p3);
s.insert(p4);
for (set<Person,myCompare>::iterator it = s.begin(); it != s.end(); it++)
{
cout << "姓名:" << it->m_Name << "年龄:" << it->m_Age << endl;
}
}
int main()
{
test01();
}
/*
姓名:刘备年龄:24
姓名:关羽年龄:23
姓名:张飞年龄:22
姓名:赵云年龄:21
*/
简介:
功能描述:
#include<iostream>
#include<map>
using namespace std;
//map容器构造和赋值
void printMap(map<int, int>& m)
{
for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
{
cout << "key=" << (*it).first << "value="<<it->second << endl;
}
cout << endl;
}
void test01()
{
map<int, int>m;
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(2, 20));
m.insert(pair<int, int>(3, 30));
m.insert(pair<int, int>(4, 40));
printMap(m);
//拷贝构造
map<int, int>m2(m);
printMap(m2);
//赋值
map<int, int>m3;
m3 = m2;
printMap(m3);
}
int main()
{
test01();
/*
key=1value=10
key=2value=20
key=3value=30
key=4value=40
*/
}
功能描述:
#include<iostream>
using namespace std;
#include<map>
void printMap(const map<int, int>& m)
{
for (map<int, int>::const_iterator it = m.begin(); it != m.end(); it++)
{
cout << "键:" << it->first << "值:" << it->second << endl;
}
cout << endl;
}
void test01()
{
map<int, int>m;
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(2, 30));
m.insert(pair<int, int>(3, 20));
if (m.empty())
{
cout << "m为空" << endl;
}
else
{
cout << "m不为空" << endl;
cout << "m的大小为:" << m.size() << endl;
}
map<int, int>m2;
m2.insert(pair<int, int>(4, 100));
m2.insert(pair<int, int>(5, 200));
m2.insert(pair<int, int>(6, 300));
//交换前
//cout << "m:" << endl;
printMap(m);
printMap(m2);
//交换后
m.swap(m2);
printMap(m);
printMap(m2);
}
int main()
{
test01();
}
/*
m不为空
m的大小为:3
键:1值:10
键:2值:30
键:3值:20
键:4值:100
键:5值:200
键:6值:300
键:4值:100
键:5值:200
键:6值:300
键:1值:10
键:2值:30
键:3值:20
*/
功能描述:
//第一种
m.insert(pair<int,int>(1,10));
//第二种
m.insert(make_pair(2,20));
//第三种
m.insert(map<int,int>::value_type(3,30));
//第四种
m[4] = 40;//不太建议用第四种插入,但是可以用key访问到value
//原因:比如前面直插入了4个键值对,这时候输出m[5]他会创建m[5]=0
删除实例:
m.erase(m.begin());
printMap(m);
m.erase(3);//按照key删除
m.erase(m.begin(),m.end());
m.clear();
功能描述:
map<int,int>m;
m.insert(make_pair(1,10));
m.insert(make_pair(2,20));
m.insert(make_pair(3,30));
m.insert(make_pair(4,40));
map<int,int>::iterator pos = m.find(3);
if (pos != m.end())
{
cout<<"查到了key="<<(*pos).first<<"value="<<pos->secend<<endl;
}
else
{
cout<<"未找到元素"<<endl;
}
学习目标:
class myCompare
{
public:
bool operator()(int v1,int v2)
{
//降序
return v1>v2;
}
}
void test01()
{
map<int,int,myCompare>m;
m.insert(make_pair(1,10));
m.insert(make_pair(2,20));
m.insert(make_pair(3,30));
for(map<int,int>::iterator it = m.begin();it != m.end();it++)
{
cout<<"key="<<it->first<<"value="<<it->second<<endl;
}
}
总结:
#include<iostream>
#include<map>
#include<vector>
#define CEHUA 0
#define YANFA 2
#define MEISHU 1
#include<ctime>
using namespace std;
class Worker
{
public:
string m_Name;
int m_Scalary;
};
void createWorker(vector<Worker>& v)
{
string nameSeed = "ABCDEFGHIJ";
for (int i = 0; i < 10; i++)
{
Worker worker;
worker.m_Name = "员工";
worker.m_Name += nameSeed[i];
worker.m_Scalary = rand() % 10000 + 10000;//10000~19999
//将员工放入到容器中
v.push_back(worker);
}
}
void setGroup(vector<Worker>& v,multimap<int,Worker>& m)
{
for (vector<Worker>::iterator it = v.begin(); it != v.end(); it++)
{
//产生随机部门编号
int deptId = rand() % 3;//0 1 2
m.insert(make_pair(deptId, *it));
}
}
//分组显示员工
void showWorkerByGourp(multimap<int, Worker>& m)
{
cout << "策划部门的信息:" << endl;
multimap<int,Worker>::iterator pos = m.find(CEHUA);
int count = m.count(CEHUA);//统计具体认识
int index = 0;
for (; pos != m.end() && index<count; pos++,index++)
{
cout << "姓名:" << pos->second.m_Name << "工资:" << pos->second.m_Scalary << endl;
}
cout << "-------------------" << endl;
cout << "美术部门信息:" << endl;
pos = m.find(MEISHU);
count = m.count(MEISHU);
index = 0;
for (; pos != m.end() && index < count; pos++, index++)
{
cout << "姓名:" << pos->second.m_Name << "工资:" << pos->second.m_Scalary << endl;
}
cout << "-------------------" << endl;
cout << "研发部门信息:" << endl;
pos = m.find(YANFA);
count = m.count(YANFA);
index = 0;
for (; pos != m.end() && index < count; pos++, index++)
{
cout << "姓名:" << pos->second.m_Name << "工资:" << pos->second.m_Scalary << endl;
}
}
int main()
{
srand((unsigned int)time(NULL));
vector<Worker>vWorker;
createWorker(vWorker);
////测试
//for (vector<Worker>::iterator it = vWorker.begin(); it != vWorker.end(); it++)
//{
// cout << (*it).m_Name << " " << it->m_Scalary << endl;
//}
//分组
multimap<int, Worker>mWorker;
setGroup(vWorker, mWorker);
showWorkerByGourp(mWorker);
}
/*
策划部门的信息:
姓名:员工D工资:16500
姓名:员工I工资:16962
姓名:员工J工资:14464
-------------------
美术部门信息:
姓名:员工C工资:16334
姓名:员工E工资:19169
姓名:员工G工资:11478
-------------------
研发部门信息:
姓名:员工A工资:10041
姓名:员工B工资:18467
姓名:员工F工资:15724
姓名:员工H工资:19358
*/
概念:
特点:
#include<iostream>
using namespace std;
class MyAdd
{
public:
int operator()(int v1, int v2)
{
return v1 + v2;
}
};
//函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值
void test01()
{
MyAdd myAdd;
cout << myAdd(10, 10) << endl;;
}
//函数对象超出普通函数的概念,函数对象可以有自己的状态
class MyPrint
{
public:
MyPrint()
{
this->count = 0;
}
void operator()(string test)
{
cout << test << endl;
this->count += 1;
}
int count;//内部自己状态
};
void test02()
{
MyPrint myPrint;
myPrint("hello print");
myPrint("hello print");
myPrint("hello print");
cout << "myPrint调用次数" << myPrint.count << endl;
}
//函数对象可以作为参数传递
void doPrint(MyPrint& mp, string test)
{
mp(test);
}
void test03()
{
MyPrint myPrint;
doPrint(myPrint, "hello c++");
}
int main()
{
//test01();
//test02();
test03();
}
概念:
实例:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//仿函数,返回值类型是bool数据类型,称为谓词
//一元谓词
class GreaterFive
{
public:
bool operator()(int val)
{
return val > 5;
}
};
void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
//查找容器中有没有大于5的数字
vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());//GreaterFive匿名函数对象
if (it == v.end())
{
cout << "未找到" << endl;
}
else
{
cout << "找到了大于五的数字" << *it << endl;
}
}
int main()
{
test01();
}
二元谓词的案例:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
//二元谓词
class MyCompare
{
public:
bool operator()(int val1, int val2)
{
return val1 > val2;
}
};
void test01()
{
vector<int>v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
sort(v.begin(), v.end());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
//使用函数对象,改变算法策略,规则为从大到小
sort(v.begin(), v.end(), MyCompare());
cout << "------------------------" << endl;
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
}
int main()
{
test01();
}
/*
10 20 30 40 50
--------------
50 40 30 20 10
*/
概念:
#include<iostream>
using namespace std;
#include<functional>
void test01()
{
negate<int>n;
cout << n(50) << endl;
}
void test02()
{
plus<int>p;
cout << p(10, 20) << endl;
}
int main()
{
test02();
}
总结:使用内建函数对象时,需要引入头文件#include
功能描述:
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<functional>
//内建函数对象_关系仿函数
//大于greater
class MyCompare
{
public:
bool operator()(int v1, int v2)
{
return v1 > v2;
}
};
void test01()
{
vector<int>v;
v.push_back(10);
v.push_back(30);
v.push_back(40);
v.push_back(20);
v.push_back(50);
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
sort(v.begin(), v.end(), MyCompare());
//降序
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
//或者也可以使用内建的函数对象,greater<>()用的较多,sort内部默认用的是less<>()
sort(v.begin(), v.end(), greater<int>());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
test01();
}
/*
10 30 40 20 50
50 40 30 20 10
50 40 30 20 10
*/
功能描述:
#include<iostream>
#include<algorithm>
#include<vector>
#include<functional>
using namespace std;
//内建函数对象,逻辑仿函数
//逻辑非 logical_not
void test01()
{
vector<bool>v;
v.push_back(true);
v.push_back(false);
v.push_back(true);
v.push_back(false);
v.push_back(true);
for (vector<bool>::iterator it = v.begin(); it != v.end(); it++ )
{
cout << *it << " ";
}
cout << endl;
//利用逻辑非将容器v搬运到容器v2中,并执行取反操作
vector<bool>v2;
v2.resize(v.size());//必须先指定大小才能顺利搬运
transform(v.begin(), v.end(), v2.begin(), logical_not<bool>());
for (vector<bool>::iterator it = v2.begin(); it != v2.end(); it++ )
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
test01();
}
/*
1 0 1 0 1
0 1 0 1 0
*/
概述:
学习目标:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//常用遍历算法,for_each
//普通函数
void print01(int val)
{
cout << val << " ";
}
//仿函数
class print02
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
for_each(v.begin(), v.end(), print01);
cout << endl;
for_each(v.begin(), v.end(), print02());//仿函数
}
int main()
{
test01();
}
/*
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
*/
功能描述:
搬运容器到另一个容器中
函数原型:
#include<iostream>
using namespace std;
#include<algorithm>
#include<functional>
#include<vector>
//常用遍历算法
class Print01
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
class Transform
{
public:
int operator()(int val)
{
return val+1000;
}
};
void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
vector<int>vTarget;//目标容器
//搬运的时候必须先给目标容器开辟空间
vTarget.resize(v.size());
transform(v.begin(), v.end(), vTarget.begin(), Transform());
for_each(vTarget.begin(), vTarget.end(), Print01());
}
int main()
{
test01();
}
/*1000 1001 1002 1003 1004 1005 1006 1007 1008 1009*/
学习目标:
功能描述:
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
//常用查找算法
//查找内置数据类型
void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
//查找是否由5这个元素
vector<int>::iterator it = find(v.begin(), v.end(), 5);
if (it == v.end())
{
cout << "没有找到:" << endl;
}
else
{
cout << "找到了:" << *it << endl;
}
}
//查找自定义数据类型
class Person
{
public:
Person(string name, int age)
{
this->m_Age = age;
this->m_Name = name;
}
//重载==让find知道如何对比
bool operator==(const Person& p)
{
if (this->m_Name == p.m_Name && this->m_Age == p.m_Age )
{
return true;
}
else
{
return false;
}
}
string m_Name;
int m_Age;
};
void test02()
{
vector<Person>v;
Person p1("aaa", 10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
Person pp("bbb", 20);
vector<Person>::iterator it = find(v.begin(), v.end(), pp);
if (it == v.end())
{
cout << "没找到" << endl;
}
else
{
cout << "找到了" << endl;
cout << "姓名:" << it->m_Name << "年龄:" << it->m_Age << endl;
}
}
int main()
{
//test01();
test02();
}
/*
找到了
姓名:bbb年龄:20
*/
总结:利用find可以在容器中查找指定地元素,返回值是迭代器
功能描述:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Person
{
public:
Person(string name, int age)
{
this->m_Age = age;
this->m_Name = name;
}
string m_Name;
int m_Age;
};
class GreaterFive
{
public:
bool operator()(int val)
{
return val > 5;
}
};
void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());
if (it == v.end())
{
cout << "没有找到:" << endl;
}
else
{
cout << "找到了:" <<*it<< endl;
}
}
class Greater20
{
public:
bool operator()(Person& p)
{
return p.m_Age > 20;
}
};
void test02()
{
vector<Person>v;
//创建数据
Person p1("aaa", 10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
//找年龄大于20的人
vector<Person>::iterator it = find_if(v.begin(), v.end(), Greater20());
if (it == v.end())
{
cout << "未找到" << endl;
}
else
{
cout << "找到了年龄大于20的人,他的姓名是:" << it->m_Name << "他的年龄是:" << it->m_Age;
}
}
int main()
{
//test01();
test02();
}
//找到了:6
//找到了年龄大于20的人,他的姓名是:ccc他的年龄是:30
功能描述:
vector<int>v;
v.push_back(0);
v.push_back(1);
v.push_back(1);
v.push_back(2);
vector<int>::iterator pos = adjacent_find(v.begin(),v.end());
if(pos == v.end())
{
cout<<"未找到相邻重复元素"<<endl;
}
else
{
cout<<"找到了相邻重复元素"<<*pos<<endl;
}
功能描述:
vector<int> v;
for(int i = 0;i<10;i++)
{
v.push_back(i);
}
//查找是否有9元素
bool ret = binary_search(v.begin(),v.end(),9);
if(ret)
{
cout<<"找到了元素"<<endl;
}
else
{
cout<<"未找到"<<endl;
}
功能描述:
#include<iostream>
using namespace std;
#include<algorithm>
#include<vector>
void test01()
{
vector<int>v;
v.push_back(10);
v.push_back(40);
v.push_back(30);
v.push_back(30);
v.push_back(30);
v.push_back(30);
v.push_back(30);
int num = count(v.begin(), v.end(), 40);
cout << "40的元素个数为:" << num << endl;
}
//统计自定义数据类型
class Person
{
public:
Person(string name, int age)
{
this->m_Age = age;
this->m_Name = name;
}
bool operator==(const Person& p)
{
return this->m_Age == p.m_Age;
}
string m_Name;
int m_Age;
};
void test02()
{
vector<Person>v;
Person p1("刘备", 34);
Person p2("张飞", 334);
Person p3("关羽", 324);
Person p4("赵云", 35);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
Person p("诸葛亮", 35);
int num = count(v.begin(), v.end(),p);
cout << "和诸葛亮同岁数的人员个数为:" << num << endl;
}
int main()
{
test02();
}
//和诸葛亮同岁数的人员个数为:1
功能描述:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//常用查找算法
//统计自定义数据类型
class Greater20
{
public:
bool operator()(int num)
{
return num > 20;
}
};
void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i * 10);
}
int num = count_if(v.begin(), v.end(),Greater20());
cout << "大于20的有:" << num << "个" << endl;
}
class Person
{
public:
Person(string name, int age)
{
this->m_Age = age;
this->m_Name = name;
}
string m_Name;
int m_Age;
};
class AgeGreater40
{
public:
bool operator()(Person& p)
{
return p.m_Age > 40;
}
};
void test02()
{
vector<Person> v;
Person p1("刘备", 34);
Person p2("张飞", 334);
Person p3("关羽", 324);
Person p4("赵云", 35);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
int num = count_if(v.begin(), v.end(), AgeGreater40());
cout << "年龄大于40的有" << num << "个" << endl;
}
int main()
{
//test01();
test02();
}
//大于20的有:7个
//年龄大于40的有2个
学习目标:
功能描述:
#include<iostream>
using namespace std;
#include<algorithm>
#include<vector>
//常用排序算法
void myPrint(int val)
{
cout << val<< " ";
}
void test01()
{
vector<int>v;
v.push_back(10);
v.push_back(30);
v.push_back(22);
v.push_back(28);
v.push_back(40);
//利用sort进行升序
sort(v.begin(), v.end());
for_each(v.begin(), v.end(), myPrint);
cout << endl;
//改变降序
sort(v.begin(), v.end(), greater<int>());
for_each(v.begin(), v.end(), myPrint);
}
int main()
{
test01();
system("pause");
}
/*
10 22 28 30 40
40 30 28 22 10
*/
功能描述:
#include<iostream>
#include<time>
#include<algorithm>
using namespace std;
#include<vector>
void myPrint(int v)
{
cout << v << " ";
}
//常用排序算法
void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
//利用洗牌算法打乱顺序
random_shuffle(v.begin(), v.end());
for_each(v.begin(), v.end(), myPrint);
cout << endl;
}
int main()
{
srand(ussigned int)time(NULL);
test01();
}
//8 1 9 2 0 5 7 3 4 6
总结:random_shuffle洗牌算法比较实用,但是使用的时候记得加上随机数种子
功能描述:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//常用排序算法merge
void myPrint(int val)
{
cout << val << " ";
}
void test01()
{
vector<int>v1;
vector<int>v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i + 1);
}
//目标容器
vector<int>vTarget;//目标容器是空的,需要提前分配内存
vTarget.resize(v1.size()+v2.size());
merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
for_each(vTarget.begin(), vTarget.end(), myPrint);
cout << endl;
}
int main()
{
test01();
}
//0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10
总结:merge合并的两个容器必须是有序的序列
功能描述:
学习目标:
功能描述:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
void myPrint(int val)
{
cout << val << " ";
}
void test01()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
vector<int>v2;
v2.resize(v1.size() - 2);
copy(v1.begin(), v1.end() - 2, v2.begin());
for_each(v2.begin(), v2.end(), myPrint);
}
int main()
{
test01();
}
//0 1 2 3 4 5 6 7
功能描述:
功能描述:
#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
using namespace std;
class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
class Greater30
{
public:
bool operator()(int val)
{
return val >= 30;
}
};
void test01()
{
vector<int>v1;
v1.push_back(10);
v1.push_back(30);
v1.push_back(60);
v1.push_back(85);
v1.push_back(3);
v1.push_back(8);
for_each(v1.begin(), v1.end(), myPrint());
replace_if(v1.begin(), v1.end(), Greater30(),3000);
cout << endl;
for_each(v1.begin(), v1.end(), myPrint());
}
int main()
{
test01();
}
/*
10 30 60 85 3 8
10 3000 3000 3000 3 8
*/
功能描述:
学习目标:
功能描述:
功能描述:
学习目标:
功能描述:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//常用集合算法,set_intersection
class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int>v1;
vector<int>v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i + 5);
}
vector<int>vTarget;
//目标容器需要提前开辟空间
vTarget.resize(v1.size() > v2.size() ? v2.size() : v1.size());
cout << "v1" << endl;
for_each(v1.begin(), v1.end(), myPrint());
cout << endl;
cout << "v2" << endl;
for_each(v1.begin(), v1.end(), myPrint());
cout << endl;
cout << "vTarget" << endl;
vector<int>::iterator itEnd = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
for_each(vTarget.begin(), vTarget.end(), myPrint());//要注意这样是不行的最后输出结果5 6 7 8 9 0 0 0 0 0
//应该要这么写
cout << endl;
for_each(vTarget.begin(), itEnd, myPrint());
}
int main()
{
test01();
}
/*
v1
0 1 2 3 4 5 6 7 8 9
v2
0 1 2 3 4 5 6 7 8 9
vTarget
5 6 7 8 9 0 0 0 0 0
5 6 7 8 9
*/
总结:求交集的俩个集合必须是有序序列
目标容器开辟空间需要从两个容器中取小值
set_intersection返回值即是交集中最后一个元素的位置
功能描述:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int>v1;
vector<int>v2;
for (int i = 0; i < 4; i++)
{
v1.push_back(i);
}
for (int i = 0; i < 7; i++)
{
v2.push_back(i + 3);
}
cout << "v1" << endl;
for_each(v1.begin(), v1.end(), myPrint());
cout << endl;
cout << "v2" << endl;
for_each(v2.begin(), v2.end(), myPrint());
cout << endl;
vector<int>vTarget;
vTarget.resize(v1.size() + v2.size());
vector<int>::iterator itEnd = set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
cout << "V1+V2" << endl;
for_each(vTarget.begin(), itEnd, myPrint());
}
int main()
{
test01();
}
/*
v1
0 1 2 3
v2
3 4 5 6 7 8 9
V1+V2
0 1 2 3 4 5 6 7 8 9
*/
总结:
功能描述:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int>v1;
vector<int>v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
for (int i = 0; i < 8; i++)
{
v2.push_back(i + 2);
}
vector<int>vTarget;
vTarget.resize(max(v1.size(),v2.size()));
vector<int>::iterator itEnd = set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
for_each(vTarget.begin(), itEnd, myPrint());
}
int main()
{
test01();
}
//0 1
总结:
本文章使用limfx的vscode插件快速发布