c++笔记(黑马程序员 面向过程、面向对象)

目录

Hello world

变量

常量

关键字

标识符命名规则

浮点型(实型)

字符型

 转义字符

字符串型

布尔类型bool

数据的输入

 运算符

算术运算符

赋值运算符

逻辑运算符

程序流程结构

选择结构

If语句

三目运算符

Switch语句(执行多条件分支语句)

循环结构

while循环

do...while循环语句

For循环语句

嵌套循环

跳转语句(用于跳出选择结构或者循环结构)

Continue语句

goto语句

数组

一维数组

一维数组数组名

练习案例1(五只小猪称体重)

练习案例2(数组元素逆置)

冒泡排序

二维数组

二维数组数组名

练习案例(考试成绩统计)

函数

函数的调用

   函数-值传递

函数的常见样式

函数的声明

函数的分文件编写

指针

指针所占的内存空间

空指针和野指针

const修饰指针

指针和数组

指针和函数

练习案例(指针,数组,函数)

结构体

结构体数组

结构体指针

结构体嵌套结构体

结构体做函数参数

结构体中const的使用场景

结构体案例1

案例练习2

内存分区模型

C++在程序运行前分为全局区和代码区

引用

引用的本质:指针常量

函数的默认参数

函数重载(提高函数复用性)

类和对象

继承

 

struct和class的区别

成员属性设置为私有

例1:封装一个长方体类

例2:判断点与圆的位置关系

构造函数和析构函数

构造函数的分类和调用

拷贝构造函数调用时机

深拷贝和浅拷贝

初始化列表

类对象作为类成员

静态成员

                 静态成员变量:

             静态成员函数:

this指针概念

Const修饰成员函数

  友元

运算符重载

                  左移运算符重载

                  递增运算符重载

赋值运算符重载

关系运算符重载

函数调用运算符重载

继承方式

继承中的对象模型

继承中构造和析构顺序

继承同名成员处理方式

继承同名静态成员处理方式

多继承语法

菱形继承

多态

案例  计算器类

纯虚函数和抽象类

虚析构和纯虚析构

文件操作

文本文件

写文件

读文件

二进制文件

写文件

读文件


Hello world

#include<iostream>

using namespace std;

int main()

{

   cout<<"hello world"<<endl;

   system("pause");

   return 0;

 }

\\endl 为换行符

变量

变量创建的语法 :数据类型 变量名 = 变量初始值;

#include<iostream>

using namespace std;

int main()

{

   int a = 10;

   cout<<"a = "<<a<<endl;

   system("pasue");

   return 0;

 }

常量

#define 宏常量:#define 常量名 常量值

   通常在文件上方定义,表示一个常量

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

   通常在变量定义前加关键字const,修饰该变量为常量,不可修改

#include<iostream>

using namespace std;

#define Day 7

int main()

{

   cout<<"一周有"<< Day <<"天"<<endl;

   system("pause");

   return 0;

 }

#include<iostream>

using namespace std;

int main()

{

   const int a = 12;

   cout<<a<<endl;

   system("pause");

   return 0;

 }

\\变量a 不可修改

关键字

创建变量时,取名不可使用关键字

标识符命名规则

  1. 不可谓关键字
  2. 只能为字母、数字、下划线
  3. 第一个字符只能为字母或者下划线
  4. 标识符中区分大小写

sizeof关键字

可以利用sizeof求出数据类型占用内存大小

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

#include<iostream>

using namespace std;

int main()

{

    short num1 = 12;

    cout<<"数据类型占用空间大小"<<sizeof(num1)<<endl;

   system("pause");

   return 0;

 }

浮点型(实型)

单精度float(有效数字 7位)

双精度double(有效数字 15-16位)

#include<iostream>

using namespace std;

int main()

{

   //默认情况下,输出一个小数,会显示出六位有效数字

   float f1 = 3.14f;

   cout<<"f1="<<f1<<endl;

   double d1 = 3.14d;

   cout<<"d1="<<d1<<endl;

   //统计float和double占用内存空间

   cout<<"float占用内存空间为:"<<sizeof(float)<<endl;

   cout<<"double占用内存空间为:"<<sizeof(double)<<endl;

   //科学计数法

   float f2 = 3e2;  //如果e后面是一个正数,则代表“3 * 10^2 ”

   cout<<"f2="<<f2<<endl;

   float f3 = 3e-2; //如果e后面是一个负数,则代表“3 * 0.1^2 ”

   cout<<"f3="<<f3<<endl;

   system("pause");

   return 0;

}

字符型

注:1、在显示字符型变量时,用单引号将字符括起来,不要用双引号

       2、单引号内只能有一个字符,不可以是字符串

       3、C和C++里字符只占用1个字节

       4、字符型变量不是把字符本身放到内存中存储,而是将对应的ASCII编码放入存储单元中

       5、ASCII表上0-31为控制字符,32-126键盘上能找到

#include<iostream>

using namespace std;

int main()

{

  //字符型变量的创建方式

  char ch = 'a';

  cout<<ch<<endl;

 

  //字符型变量所占存储空间大小

  cout<<sizeof(ch)<<endl;

 

  //字符型变量常见错误

  //char ch2 = "b";  创建字符型变量时,要用单引号

  //char ch2 = 'abc';  创建字符型变量时,单引号内只能有一个字符

   

  //字符型变量对应ASCII编码   常用: a = 97    A = 65

  cout<<(int)ch<<endl; //(int)ch  指将ch强制转换成整型

  system("pause");

 }

 
转义字符

7a835d97c4eb4f1e91b59a1a37ae0720.png

#include<iostream>

using namespace std;

int main()

{

    //转义字符

  

   //换行符  \n

   cout<<"hello world"<<endl;

   //反斜杠  \\  第一个\表示接下来输出的是特殊字符

   cout<<"\\"<<endl;

   //水平制表符   \t   作用:整齐的输出数据

   cout<<"aaa\thello world"<<endl;

   cout<<"aaaa\thello world"<<endl;

   cout<<"aaaaa\thello world"<<endl;

   system("pause");

 }

字符串型

        1、c语言风格:char 变量名[] = "字符串值";

注意:char 字符串名 []

      等号后面要用双引号包含起来字符串

#include<iostream>

using namespace std;

int main()

{

   char str[] = "hello world";

   cout<<str<<endl;

   return 0;

 }

         2、c++风格:string str1 = "hello world";

注意:要包含一个头文件       #include<string>

#include<iostream>

using namespace std;

#include<string>//头文件

int main()

{

   string str1 = "hello world";

   cout<<str1<<endl;

   system("pause");

 }

布尔类型bool

作用:表示真假的值

#include<iostream>

using namespace std;

int main()

{

   //创建bool数据类型

   bool flag = true;  //true代表真

   cout<<flag<<endl;

   flag = false;  //false代表假

   cout<<flag<<endl;

   //本质上:1代表真   2代表假

   //查看bool类型所占内存

   cout<<sizeof(bool)<<endl;

   system("pause");

 }

数据的输入

cin>>变量

整型:

#include<iostream>

using namespace std;

int main()

{

   int a = 0;

   cout<<"请给整型变量a赋值"<<endl;

   cin>>a;

   cout<<"整型变量a = "<<a<<endl;

   system("pause");

 }

布尔类型:

#include<iostream>

using namespace std;

int main()

{

   bool a = false;

   cout<<"请给布尔类型a赋值"<<endl;

   cin>>a;

   cout<<"布尔类型a = "<<a<<endl;

   system("pause");

 }   //除了0以外都是真,输出1

 
运算符

算术运算符

fe77406763984c84a53a4dc4b5e4840d.png

 注:两个整数相除,结果依然是整数,将小数部分除去

两数相除,除数不可以为零

两个小数不可以做取模(余数)运算

#include<iostream>

using namespace std;

int main()

{

  //前置递增

  int a = 10;

  ++a; //让变量+1

  cout<<"a="<<a<<endl;

  //后置递增

  int b = 10;

  b++; //让变量+1

  cout<<"b="<<b<<endl;

  //前置与后置的区别

  //前置递增:先让变量+1,然后进行表达式运算

  int a2 = 10;

  int b2 = ++a2 * 10;

  cout<<"a2="<<a2<<endl;

  cout<<"b2="<<b2<<endl;

  //后置递增:先进行表达式运算,后让变量+1

  int a3 = 10;

  int b3 = a3++ * 10; //先将值代入,运算结束赋予b3后,a3再进行+1

  cout<<"a3="<<a3<<endl;

  cout<<"b3="<<b3<<endl;

  system("pause");

 }

赋值运算符

a + = 2 //表示 a = a + 2

逻辑运算符

d1f5a0fbb35f44c285e71f2d10e52b1e.png

程序流程结构

选择结构

If语句

单行格式if语句

#include<iostream>

using namespace std;

int main()

{

  //选择结构 单行 if从句

  //用户输入分数,若分数大于 600,视为考上一本大学,并输出

 

  //用户输入分数

  int score = 0;

  cout<<"请输入一个分数"<<endl;

  cin>>score;

  //打印用户输入的分数

  cout<<"您输入的分数为:"<<score<<endl;

  //判断分数是否大于600,若大于,输出

  if(score>600)

  {

    cout<<"恭喜您考上了一本大学"<<endl;

  }

  system("pause");

  return 0;

}

注:if后不加 分号



多行格式if语句

#include<iostream>

using namespace std;

int main()

{

  //选择结构 - 多行if语句

  //输入考试分数,若分数大于600,视为考上一本大学,在屏幕上输出,若没考上,打印未考上一本大学

  //输入考试成绩

  int score = 0;

  cout<<"请输入考试成绩"<<endl;

  cin>>score;

  //提示用户输入的分数

  cout<<"您输入的分数为"<<score<<endl;

  //判断 若大于600,打印考上一本,否则打印未考上一本

  if(score>600)

  {

    cout<<"恭喜考上一本大学"<<endl;

  }

  else

  {

    cout<<"名落孙山"<<endl;

  }

  system("pause");

  return 0;

 }

多条件的if语句

if条件(条件1),else if(条件2),else(条件3)…

#include<iostream>

using namespace std;

int main()

{

  //选择结构 - 多条件if语句

  //输入考试分数,若分数大于600,视为考上一本大学,在屏幕上输出,若没考上,打印未考上一本大学

  //大于500分,视为考上二本大学,在屏幕上输出

  //大于400分,视为考上三本大学,在屏幕上输出

  //小于等于400,视为未考上大学,在屏幕上输出

  //输入考试成绩

  int score = 0;

  cout<<"请输入考试成绩"<<endl;

  cin>>score;

  //提示用户输入的分数

  cout<<"您输入的分数为"<<score<<endl;

  //判断 若大于600,打印考上一本

  //若大于500,打印考上二本

  //若大于400,打印考上三本

  //都不满足,打印名落孙山

  if(score>600)

  {

    cout<<"恭喜考上一本大学"<<endl;

  }

  else if(score>500)

  {

    cout<<"恭喜考上二本大学"<<endl;

  }

  else if(score>400)

  {

    cout<<"恭喜考上三本大学"<<endl;

   }

  else

   {

     cout<<"名落孙山"<<endl;

   }

  system("pause");

  return 0;

 }

嵌套if语句

#include<iostream>

using namespace std;

int main()

{

  //选择结构 - 嵌套if语句

  //输入考试分数,若分数大于500,视为考上一本大学,在屏幕上输出,若没考上,打印未考上一本大学

  //大于400分,视为考上二本大学,在屏幕上输出

  //大于300分,视为考上三本大学,在屏幕上输出

  //小于等于300,视为未考上大学,在屏幕上输出

  //在一本分数中,大于700分,考入北大,大于650分,考入清华,大于600分,考入人大

  //输入考试成绩

  int score = 0;

  cout<<"请输入考试成绩"<<endl;

  cin>>score;

  //提示用户输入的分数

  cout<<"您输入的分数为"<<score<<endl;

  //判断 若大于500,打印考上一本

  //若大于400,打印考上二本

  //若大于300,打印考上三本

  //都不满足,打印名落孙山

  if(score>500)

  {

    cout<<"恭喜考上一本大学"<<endl;

    if(score>700)

    {

       cout<<"恭喜考入北大"<<endl;

     }

    else if(score>650)

    {

       cout<<"恭喜考入清华"<<endl;

    }

    else if(score>600)

    {

       cout<<"恭喜考入人大"<<endl;

    }

  }

  else if(score>500)

  {

    cout<<"恭喜考上二本大学"<<endl;

  }

  else if(score>400)

  {

    cout<<"恭喜考上三本大学"<<endl;

   }

  else

   {

     cout<<"名落孙山"<<endl;

   }

  system("pause");

  return 0;

 }

练习案例:三只系小猪称体重

有三只小猪ABC,分别输入三只小猪的体重,并判断哪只小猪最重

#include<iostream>

using namespace std;

int main()

{

//先判断A和B谁重,在与C比较

int a = 0;

int b = 0;

int c = 0;

cout<<"请输入小猪A的重量"<<endl;

cin>>a;

cout<<"请输入小猪B的重量"<<endl;

cin>>b;

cout<<"请输入小猪C的重量"<<endl;

cin>>c;

cout<<"小猪A的重量为:"<<a<<endl;

cout<<"小猪B的重量为:"<<b<<endl;

cout<<"小猪C的重量为:"<<c<<endl;

if(a>b)

{

   if(a>c)

   {

      cout<<"小猪A为最重的:"<<a<<endl;

   }

   else if(a<c)

   {

      cout<<"小猪C为最重的:"<<c<<endl;

    }

}

else if(a<b)

{

      if(b>c)

   {

      cout<<"小猪B为最重的:"<<b<<endl;

   }

   else if(b<c)

   {

      cout<<"小猪C为最重的:"<<c<<endl;

    }

}

system("pause");

return 0;

 }

三目运算符

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

解释:若表达式1的值为真,执行表达式2,并返回表达式2的结果

若表达式1的值为假,执行表达式3,并返回表达式3的结果

#include<iostream>

using namespace std;

int main()

{

   //三目运算符

   //创建三个变量

   //将a和b作比较,将变量大的值赋值给c

   int a = 10;

   int b = 20;

   int c = 0;

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

   cout<<c<<endl;

  

   //三目运算符返回的是变量,可以继续赋值

   (a<b ? a:b) = 100;

   cout<<a<<endl;

   cout<<b<<endl;

   system("pause");

   return 0;

 }

Switch语句(执行多条件分支语句)

switch  case  break  default(相当于else)

#include<iostream>

using namespace std;

int main()

{

   //switch 语句

   //给电影打分

   //10-9 经典

   //8-7  非常好

   //6-5  一般

   //5以下  烂片

  

   //提示用户给电影打分

   cout<<"请给电影进行打分"<<endl;

   //用户进行打分

   int score = 0;

   cin>>score;

   cout<<"您打的分数为:"<<score<<endl;

   //根据用户输入的分数来提示用户最后的结果

   switch(score)

   {

     case 10:

     cout<<"您认为是经典"<<endl;

     break;

     case 9:

     cout<<"您认为是经典"<<endl;

     break;

     case 8:

     cout<<"非常好"<<endl;

     break;

     case 7:

     cout<<"非常好"<<endl;

     break;

     case 6:

     cout<<"一般"<<endl;

     break;

     case 5:

     cout<<"一般"<<endl;

     break;

     default:

     cout<<"烂片"<<endl;

     break;

    }

    //if 和 switch 的区别

    //switch 缺点:判断分支时,只能是整型或者字符型,不可以是区间

    //switch 优点:结构清晰,执行效率高

   system("pause");

   return 0;

 }

循环结构

while循环

While(循环条件)(循环语句)

#include<iostream>

using namespace std;

int main()

{

   //while 循环

   //屏幕上打印0~9十个数

   int num = 0;

   while(num<10)

   {

     cout<<num<<endl;

     num++;

    }

   system("pause");

   return 0;

 }

案例练习

    系统随机生成一个1-100之间的数字,玩家进行猜测,若猜错,提示玩家数字过大或过小,若猜对,恭喜玩家胜利,结束游戏。

#include<iostream>

#include<cstdlib> // rand()和srand() 包含在这个库中

#include<ctime> //time 系统时间头文件

using namespace std;

int main()

{

cout << "\t----------" << endl; //  \t 为水平制表符

cout << "\t|猜数游戏|(1-100)" << endl;

cout << "\t----------" << endl;

cout<<"请玩家进行猜测"<<endl;

//添加随机数种子,作用:利用系统当前的时间生成随机数,防止每次随机数都一样

srand((unsigned int)time(NULL));

//系统生成一个随机数

int num1 = rand() % 100+1;  //rand()%100  生成0-99的随机数

//玩家进行猜测

int num2 = 0;  //玩家输入的数据

int a = 0; //统计猜测次数

while(1)

{

   cin>>num2;

   //判断玩家的猜测

    if(num2>num1)

       {

       cout<<"猜测过大"<<endl;

       a++;

    }

    else if(num2<num1)

    {

       cout<<"猜测过小"<<endl;

       a++;

    }

    else

      {

         cout<<"恭喜猜对了"<<endl;

         a++;

         break;

     } 

//猜对 退出游戏

//猜错 提示猜的结果,返回第二步

if(a == 7)

{

   cout<<"猜测次数过多,你输了!"<<endl;

 }

}

system("pause");

return 0;

 }

do...while循环语句

do(循环语句) while(循环条件)

 注:与while的区别在于do…while会先进行一次循环语句,再判断循环条件

     while是先判断循环条件,再执行循环语句

#include<iostream>

#include<cstdlib> // rand()和srand() 包含在这个库中

#include<ctime> //time 系统时间头文件

using namespace std;

int main()

{

cout << "\t----------" << endl; //  \t 为水平制表符

cout << "\t|猜数游戏|(1-100)" << endl;

cout << "\t----------" << endl;

cout<<"请玩家进行猜测"<<endl;

//添加随机数种子,作用:利用系统当前的时间生成随机数,防止每次随机数都一样

srand((unsigned int)time(NULL));

//系统生成一个随机数

int num1 = rand() % 100+1;  //rand()%100  生成0-99的随机数

//玩家进行猜测

int num2 = 0;  //玩家输入的数据

int a = 0; //统计猜测次数

while(1)

{

   cin>>num2;

   //判断玩家的猜测

    if(num2>num1)

       {

       cout<<"猜测过大"<<endl;

       a++;

    }

    else if(num2<num1)

    {

       cout<<"猜测过小"<<endl;

       a++;

    }

    else

      {

         cout<<"恭喜猜对了"<<endl;

         a++;

         break;

     } 

//猜对 退出游戏

//猜错 提示猜的结果,返回第二步

if(a == 7)

{

   cout<<"猜测次数过多,你输了!"<<endl;

 }

}

system("pause");

return 0;

 }

练习案例:水仙花数

 水仙花数是指一个3位数,它的每个位上的数字的三次幂之和等于它本身

 例如:1^3+5^3+3^3=153

请用do……while语句,求出所有3位数中的水仙花数

1、将所有的三位数进行输出(100-999)

2、在所有三位数中找到水仙花数

思路分析:   

       水仙花数

   获得个位   153%10=3  直接取模于10

   获得十位   153/10=15  15%10=5 先整除10,再取模于10

   获得百位    153/100=1

#include<iostream>

using namespace std;

int main()

{

//先打印所有的三位数

int num = 100;

int a = 0; //个位

int b = 0; //十位

int c = 0; //百位

while(num<1000)

{

   a = num%10;

   b = num/10 %10;

   c = num/100;

   if(a*a*a + b*b*b + c*c*c == num)  //如果是水仙花数,则打印

   {

      cout<<num<<endl;

   }

   num++;

 }

//从所有的三位数中找到水仙花数

   

system("pause");

return 0;

}

For循环语句

for(起始表达式;条件表达式;末尾循环体)

{ 循环语句 }

#include<iostream>

using namespace std;

int main()

{

//for循环

//从数字0 打印到 数字9

for(int a=0;a<10;a++)

{

   cout<<a<<endl;

 }

system("pause");

return 0;

}

案例练习(敲桌子)

  从1开始数到100,如果数字个位含有7,或者十位有7,或者是7的倍数,我们打印敲桌子,其余数字直接打印输出

 思路分析:

  1. 先输出1-100
  2. 从100个数字中找到特殊的数字,改为输出敲桌子
  3. Num%7=0

Num/10%10=7

Num/10=7 

 #include<iostream>

using namespace std;

int main()

{

   //先输出1-100

   int a = 0,b = 0,c = 0;

   for(int num = 1;num<101;num++)

   {

     a = num%7;

     b = num/10%10;

     c = num/10;

     if(a == 0 || b == 7 || c == 7)

     {

        cout<<"敲桌子"<<endl;

     }

     else

     {

        cout<<num<<endl;

     }

    }

   system("pause");

   return 0;

}

嵌套循环

#include<iostream>

using namespace std;

int main()

{

   //利用嵌套循环实现星图

    for(int a = 0;a<10;a++)

    {

      for(int b = 0;b<10;b++)

       {

         cout<<"* ";

       }

       cout<<endl;

   }

   system("pause");

   return 0;

}

练习案例(乘法口诀表)

#include<iostream>

using namespace std;

int main()

{

   int a = 1;

   for(int i = 1;i<10;i++)

   {

     for(int j = 1;j  <=i;j++)

     {

        cout<<j<<"*"<<i<<"="<<i*j<<" ";

     }

     cout<<endl;

   }

   system("pause");

   return 0;

}

跳转语句(用于跳出选择结构或者循环结构)

  使用时机:

  1. 出现在switch条件语句中,作用是终止case并跳出switch
  2. 出现在循环语句中,作用是跳出当前的循环语句
  3. 出现在嵌套循环中,跳出最近的内层循环语句
#include<iostream>

using namespace std;

int main()

{

  //break的使用时机

 

  //出现在switch语句中

  /*cout<<"请选择副本的难度"<<endl;

  cout<<"1.普通"<<endl;

  cout<<"2.中等"<<endl;

  cout<<"3.困难"<<endl;

  int selet = 0;

  cin>>selet;

  switch(selet)

  {

     case 1:

         cout<<"您选择的是普通难度"<<endl;

         break;//退出switch语句

     case 2:

         cout<<"您选择的是中等难度"<<endl;

         break;

     case 3:

         cout<<"您选择的是困难难度"<<endl;

         break;

   } */

   

  //出现在循环语句中

  /*for(int i = 0;i<10;i++)

  {

     //如果i=5,退出循环,不在打印

     if(i==5)

     {

        break;//退出循环

      }

     cout<<i<<endl;

  }*/

 

  //出现在嵌套循环语句中

  for(int i=0;i<10;i++)

  {

     for(int j=0;j<=10;j++)

     {

        if(j==5)

        {

          break;//退出内层循环

        }

        cout<<"* ";

     }

     cout<<endl;

   }

  system("pause");

  return 0;

}

Continue语句

 在循环语句中,跳过本次循环中余下尚未执行的语句,继续执行下一次循环

#include<iostream>

using namespace std;

int main()

{

  //continue语句的用途

  for(int i = 0;i<=100;i++)

  {

     //如果是奇数输出,偶数不输出

     if(i%2==0)

     {

        continue;//可以筛选条件,执行到此就不再向下执行,执行下一次循环

      }

     cout<<i<<endl;

   }

  system("pause");

  return 0;

}

goto语句

     可以无条件跳转语句

如果标记的名称存在,执行到goto语句时,会跳转到标记的位置

        一般格式:

goto FLAG;

        其他语句

FLAG:

#include<iostream>

using namespace std;

int main()

{

   //goto语句

   cout<<"1、xxxx"<<endl;

   cout<<"2、xxxx"<<endl;

   goto FLAG;

   cout<<"3、xxxx"<<endl;

   cout<<"4、xxxx"<<endl;

   FLAG:

   cout<<"5、xxxx"<<endl;

   system("pause");

   return 0;

}

数组

  1. 数组中每个元素都是相同的数据类型
  2. 数组是由连续的内存位置组成的

一维数组

  1. 数据类型  数组名【数组长度】;
  2. 数据类型  数组名【数组长度】 = {值1,值2…};
  3. 数据类型  数组名【 】 = {值1,值2…};
#include<iostream>

using namespace std;

int main()

{

  //数组

  //1、数据类型  数组名[数组长度];

  int arr[5];

  //给数组中的元素进行赋值

  //数组元素的下标是从0开始索引的

  arr[0] = 10;

  arr[1] = 20;

  arr[2] = 30;

  arr[3] = 40;

  arr[4] = 50;

  //访问数据元素

  cout<<arr[0]<<endl;

  cout<<arr[1]<<endl;

  cout<<arr[2]<<endl;

  cout<<arr[3]<<endl;

  cout<<arr[4]<<endl;

 

  //2、数据类型  数组名[数组长度] = {值1,值2...};

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

  int arr1[5] = {10,20,30,40,50};

  //利用循环输出数组中的元素

  for(int i = 0;i<5;i++)

  {

     cout<<arr1[i]<<endl;

   }

 

  //3、数据类型  数组名[ ] = {值1,值2...};

  //定义数组时,必须有初始长度

  int arr2[] = {10,20,30,40,50};

  for(int j = 0;j<5;j++)

  {

     cout<<arr2[j]<<endl;

  }

  system("pause");

  return 0;

}

一维数组数组名

用途:1、可以统计整个数组在内存中的长度

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

注:首地址:该变量所占的存储区域中的第一个单元的地址

        数组名是常量,不可以赋值

#include<iostream>

using namespace std;

int main()

{

   //可以通过数组名统计整个数组占用内存大小

   int arr[10] = {1,2,3,4,5,6,7,8,9,10};

   cout<<"整个数组占用内存空间为:"<<sizeof(arr)<<endl;

   cout<<"每个元素占用内存空间为:"<<sizeof(arr[0])<<endl;

   cout<<"数组中元素的个数为:"<<sizeof(arr)/sizeof(arr[0])<<endl;

  

   //可以通过数组名查看数组首地址

   cout<<"数组的首地址为:"<<arr<<endl;

    cout<<"数组中第一个元素地址为:"<<&arr[4]<<endl;

   system("pause");

   return 0;

}

练习案例1(五只小猪称体重)

     在一个数组中记录了五只小猪的体重,如:int arr[5] = {300,350,200,400,250},找到并打印最重的小猪

#include<iostream>

using namespace std;

int main()

{

   //创建5只小猪体重的数组

   int arr[5] = {300,350,200,400,250};

   //从数组中找最大值

   int max = 0; //先认定一个最大值0

    for(int i = 0;i<5;i++)

   {

     if(arr[i]>max)

     {

        max = arr[i];

     }

    }

    //打印最大值

   cout<<"最重的小猪体重为:"<<max<<endl;

   system("pause");

   return 0;

}

练习案例2(数组元素逆置)

   请声明一个5个元素的数组,并且将元素逆置

#include<iostream>

using namespace std;

int main()

{

   //实现数组元素的逆置

   //创建数组

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

   cout<<"数据逆置前:"<<endl;

   for(int i = 0;i<5;i++)

   {

     cout<<arr[i]<<endl;

    }

   //实现逆置

   //记录起始下标的位置

   //记录结束下标的位置

   //起始下标与结束下标的元素互换

   //起始位置++  结束位置--

   int start = 0;  //起始下标

   int end = sizeof(arr) / sizeof(arr[0])-1;  //结束下标   sizeof(arr)/sizeof(arr[0]) 求出整个数组中元素个数

   while(start<end)

   {

     int temp = arr[start];

       arr[start] = arr[end];

       arr[end] = temp;

       start++;

       end--;

   }

   //打印逆置后的数组

   cout<<"数据逆置后:"<<endl;

   for(int i = 0;i<5;i++)

   {

     cout<<arr[i]<<endl;

    }

   system("pause");

   return 0;

 }

冒泡排序

作用:最常用的排序算法,对数组内元素进行排序

  1. 比较相邻的元素,若第一个比第二个打,则交换他俩
  2. 对每一对相邻元素做同样的工作,执行完毕后,找到第一个最大值
  3. 重复以上操作,每次比较次数-1,直到不需要比较
#include<iostream>

using namespace std;

int main()

{

  //利用冒泡排序实现升序序列

  int arr[9] = {4,2,8,0,5,7,1,3,9};

  cout<<"排序前:"<<" ";

  for(int i = 0;i<9;i++)

  {

     cout<<arr[i]<<" ";

  }

  cout<<endl;

  //开始冒泡排序

  //排序总轮数 = 元素个数 - 1

  //每轮对比次数 = 元素个数 - 排序轮数 - 1

  for(int i = 0;i<9-1;i++)  //i 表示总轮数

  {

     //内层的循环对比

     for(int j = 0;j<9-i-1;j++)  //j 表示每轮对比数

     {

        //如果第一个数字比第二个数字大,交换这俩数字

        if(arr[j]>arr[j+1])

        {

          int temp = arr[j];

          arr[j] = arr[j+1];

          arr[j+1] = temp;

         }

      }

  }

  //排序后结果

  cout<<"排序后:";

  for(int i = 0;i<9;i++)

  {

     cout<<arr[i]<<" ";

   }

  cout<<endl;

  system("pause");

  return 0;

 }

二维数组

定义方式:

  1. 数据类型 数组名[行数][列数];
  2. 数据类型 数组名[行数][列数]={{数据1,数据2},{数据1,数据2}};
  3. 数据类型 数组名[行数][列数]={数据1,数据2,数据3,数据4};
  4. 数据类型 数组名[ ][列数]={ 数据1,数据2,数据3,数据4};

二维数组数组名

  1. 查看二维数组所占内存空间
  2. 获取二维数组首地址
#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<<"二维数组行数为:"<<sizeof(arr)/sizeof(arr[0])<<endl;

   cout<<"二维数组列数为:"<<sizeof(arr[0])/sizeof(arr[0][0])<<endl;

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

  cout<<"二维数组首地址为:"<<arr<<endl;

  cout<<"二维数组第一行首地址为:"<<arr[0]<<endl;

  cout<<"二维数组第二行首地址为:"<<arr[1]<<endl;

  cout<<"二维数组第一个元素首地址:"<<&arr[0][0]<<endl; //查看元素首地址时要加 ‘& ’

  cout<<"二维数组第二个元素首地址:"<<&arr[0][1]<<endl;

  system("pause");

  return 0;

}

练习案例(考试成绩统计)

         有三名同学(张三,李四,王五),在一次考试中的成绩分别如下表,请分别输出三名同学的总成绩

语文

数学

英语

张三

100

100

100

李四

90

50

100

王五

60

70

80

思路:1、创建二维数组(三行三列)

           2、统计考试成绩,让每行的三列相加,统计出总和

#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] = {"张三","李四","王五"}; 

  //统计每个人的总和分数

  for(int i = 0;i<3;i++)

  {

     int sum = 0; //统计分数总和变量

     for(int j = 0;j<3;j++)

     {

        sum += score[i][j];

        //cout<<score[i][j]<<" ";

     }

     cout<<name[i]<<"的总分为:"<<sum<<endl;

   }

  system("pause");

  return 0;

}

函数

作用:将一段经常使用的代码封装起来,减少重复代码

   函数的定义

步骤:1、返回值类型

           2、函数名

           3、参数表列

           4、函数体语句

           5、return 表达式

返回值类型  函数名  (参数列表)

{

       函数体语句

       return 表达式

}

函数的调用

#include<iostream>

using namespace std;

//定义加法函数

int add(int num1,int num2)

{

   int sum = num1 + num2;

   return sum;

 }

int main()

{

   //main函数中调用add函数

   int a = 10,b = 20;

   //函数调用语法

   int c = add(a,b);

   cout<<"c = "<<c<<endl;

   system("pause");

   return 0;

 }

   函数-值传递

#include<iostream>

using namespace std;

//值传递

//定义函数,实现两个数字进行交换函数

void swap(int num1,int num2)

{

   cout<<"交换前:"<<endl;

   cout<<"num1 = "<<num1<<endl;

   cout<<"num2 = "<<num2<<endl;

   int temp = num1;

   num1 = num2;

   num2 = temp;

   cout<<"交换后:"<<endl;

   cout<<"num1 = "<<num1<<endl;

   cout<<"num2 = "<<num2<<endl;

   //返回值不需要的时候可以不写return

}

 //如果函数不需要返回值,声明的时候可以写void

int main()

{

   int a = 10,b = 20;

   //当我们做值传递的时候,函数形参发生改变,并不影响实参

   swap(a,b);

   cout<<"a = "<<a<<endl;

   cout<<"b = "<<b<<endl;

   system("pause");

   return 0;

 }

函数的常见样式

                                无参无反

void test1()

{

     cout<<“this is test1”<<endl;

}

                                有参无反

void test2(int a)

{

    cout<<“this is test2 a = ”<<a<<endl;

}

                                有参有反

int test3(int a)

{

cout<<“this is test3 a = ”<<a<<endl;

return 1000;

}

                                 无参有反

void test4()

{

     cout<<“this is test4”<<endl;     return 1000;

}

函数的声明

#include<iostream>

using namespace std;

//函数的声明

//比较函数,实现两个整型数字进行比较,返回较大的值

//声明可以写多次,但是定义只能一次

int max(int a,int b);

int main()

{

   int a = 10,b = 20;

   cout<<max(a,b)<<endl;

   system("pause");

   return 0;

 }

 int max(int a,int b)

{

   return a>b ? a : b; //三目运算符

 }

函数的分文件编写

步骤:1、创建后缀名为 .h 的头文件

           2、创建后缀名为 .cpp 的源文件

           3、在头文件中写函数的声明

           4、在源文件中写函数的定义

指针

作用:通过指针间接访问内存

  1. 内存编号是从0开始记录的,一般用十六进制
  2. 可以利用指针变量保存地址
#include<iostream>

using namespace std;

int main()

{

   //1、定义指针

   int a = 10;

   //指针定义的语法:数据类型 * 指针变量名;

   int *p; //p 代表point

   //让指针建立变量a 的地址

   p = &a;

   cout<<"a的地址为:"<<&a<<endl;

   cout<<"p = "<<p<<endl;

   //2、使用指针

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

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

   *p = 1000;

   cout<<"a = "<<a<<endl;

   cout<<"*p = "<<*p<<endl;

   system("pause");

   return 0;

 }

指针所占的内存空间

32位操作系统下占4个字节

64位操作系统下占8个字节

#include<iostream>

using namespace std;

int main()

{

   //指针所占内存空间

   int a = 10;

   int * p = &a;

   cout<<"sizeof (int *) = "<<sizeof(int *)<<endl;

   cout<<"sizeof (int *) = "<<sizeof(float *)<<endl;

   cout<<"sizeof (int *) = "<<sizeof(double *)<<endl;

   cout<<"sizeof (int *) = "<<sizeof(char *)<<endl;

   system("pause");

   return 0;

 }

空指针和野指针

空指针:指针变量指向内存中编号为0的空间

        用途:初始化指针变量(不知道指向哪,就用空指针)

注:空指针指向的内存不可访问

#include<iostream>

using namespace std;

int main()

{

   //空指针

   //空指针不可访问,0~255之间的内存编号是系统占用的,因此不可访问

   int * p = NULL; //NULL代表0

   *p = 100;

   system("pause");

   return 0;

 }

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

总:空指针和野指针都不是我们申请的空间,因此不要访问

const修饰指针

三种情况:

                1、const修饰指针——常量指针

              const int * p = &a;

(指针的指向可以修改,指向的值不可以改)

                  2、const修饰常量——指针常量

              int * const p = &a;

    (指针的指向不可以改,指向的值可以改)

                  3、const既修饰常量,又修饰指针

               const int * const p = &a;

     (指针的指向和值都不可改)

指针和数组

作用:利用指针访问数组元素

#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;

   p++;  //让指针向后偏移4个字节

   cout<<"利用指针访问第二个元素"<<*p<<endl;*/

   for(int i = 0;i<10;i++)

    {

        cout<<*p<<endl;

        p++;

    }

   system("pause");

   return 0;

 }

指针和函数

作用:利用指针作函数参数,可以修改实参的值

#include<iostream>

using namespace std;

//实现两个数字进行交换

void swap(int a,int b)

{

    int temp = a;

    a = b;

    b = temp;

    cout<<"swap a = "<<a<<endl;

    cout<<"swap b = "<<b<<endl;

}

void swap1(int * p1,int * p2)

{

    int temp = *p1;

    *p1 = *p2;

    *p2 = temp;

}

int main()

{

    //指针和函数

    //1、值传递

    int a = 10;

    int b = 20;

    //swap(a,b)

    //地址传递

    //如果是地址传递,可以修饰实参

    //地址本身不变,但是地址所对应的元素交换,所有可以修饰实参

    swap1(&a,&b);

    cout<<"a = "<<a<<endl;

    cout<<"b = "<<b<<endl;

    //2、地址传递

    cout<<

    system("pause");

    return 0;

}

练习案例(指针,数组,函数)

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

(例如: int arr[10]={4,3,6,9,1,2,10,8,7,5};)

#include<iostream>

using namespace std;

//冒泡排序函数  参数1:数组首地址   参数2:数组长度

void balabala(int *arr,int len)

{

    for(int i = 0;i<len-1;i++) //排序总轮数=元素个数-1

    {

        for(int j = 0;j<len - i - 1;j++) //每轮对比次数=元素个数-排序总轮数-1

        {

            //如果j>j+1的值,交换数字

            if(arr[j]>arr[j+1])

            {

                int temp = arr[j];

                arr[j] = arr[j+1];

                arr[j+1] = temp;

            }

        }

    }

}

//打印数组函数

void printArray(int *arr,int len)

{

    for(int i = 0;i<len;i++)

    {

        cout<<arr[i]<<endl;

    }

}

int main()

{

    //1、先创建一个数组

    int arr[10] = {4,3,6,9,1,2,10,8,7,5};//数组名即为数组首地址

    //数组长度

    int len = sizeof(arr)/sizeof(arr[0]);

    //2、创建一个函数实现冒泡排序

    balabala(arr,len);

    //3、打印排序后的数组

    printArray(arr,len);

    system("pause");

    return 0;

}

结构体

结构体属于用户自定义的数据类型,允许用户存储不同的数据类型

定义: struct 结构体名 {结构体成员列表}

方式:   1、struct 结构体名 变量名

              2、struct 结构体名 变量名 = {成员1值,成员2值…}

              3、定义结构体时顺便创建变量

#include<iostream>

#include<string>

using namespace std;

//1、创建学生数据类型    学生包括:姓名,年龄,分数

//自定义的数据类型,一些类型集合组成的一个类型

struct student

{

    //成员列表

    //姓名

    string name;

    //年龄

    int age;

    //分数

    int score;

}s3;  //顺便创建结构体变量

//2、通过学生的类型创建具体的学生

int main()

{

    //2.1 struct student s1

    //struct 关键字可以省略    //student s1;

    struct student s1;

    //给s1属性赋值,通过.访问结构体变量中的属性

    s1.name = "张三";

    s1.age = 18;

    s1.score = 100;

    cout<<"姓名:"<<s1.name<<" 年龄:"<<s1.age<<" 分数:"<<s1.score<<endl;

    //2.2 struct student s2 = {...}

    struct student s2 = {"李四",19,80};

    cout<<"姓名:"<<s2.name<<" 年龄:"<<s2.age<<" 分数:"<<s2.score<<endl;

    //2.3 在定义结构体的时候顺便创建结构体变量

    s3.name = {"王五"};

    s3.age = 20;

    s3.score = 60;

    cout<<"姓名:"<<s3.name<<" 年龄:"<<s3.age<<" 分数:"<<s3.score<<endl;

    system("pause");

    return 0;

}

结构体数组

作用:将自定义的结构体放入到数组中方便维护

语法:struct  结构体  数组名[元素个数] = {{},{},…{}};

#include<iostream>

#include<string>

using namespace std;

//结构体数组

//1、创建(定义)一个结构体

struct student

{

    //姓名

    string name;

    //年龄

    int age;

    //分数

    int score;

};

int main()

{

    //2、创建结构体数组

    struct student arr[3] =

    {

        {"张三",18,100},

        {"李四",19,80},

        {"王五",20,60}

    };

    //3、给结构体数组中的元素赋值

    arr[2].name = "赵六";

    arr[2].age = 38;

    arr[2].score = 88;

    //4、遍历结构体数组

    for(int i = 0;i<3;i++)

    {

        cout<<"姓名:"<<arr[i].name

        <<" 年龄:"<<arr[i].age

        <<" 分数:"<<arr[i].score<<endl;

    }

    system("pause");

    return 0;

}

结构体指针

作用:通过指针访问结构体中的成员

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

#include<iostream>

#include<string>

using namespace std;

//结构体指针

struct student

{

    string name;

    int age;

    int score;

};

int main()

{

    //创建学生的结构体变量

    struct student s = {"张三",18,100};

    //通过指针指向结构体变量

    struct student *p = &s;

    //通过指针访问结构体变量中的数据

    //通过结构体指针访问结构体中的属性,需要利用  ->  

    cout<<"姓名:"<<p->name<<" 年龄:"<<p->age<<" 分数:"<<p->score<<endl;

    system("pause");

    return 0;

}

结构体嵌套结构体

作用:结构体中的成员可以是另一个结构体

#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 = 1234567;

    t.name = "老王";

    t.age = 54;

    t.stu.name = "张三";

    t.stu.age = 18;

    t.stu.score = 89;

    cout<<"老师姓名:"<<t.name<<" 老师编号:"<<t.id<<" 老师年龄:"<<t.age<<endl

    <<"老师辅导的学生姓名:"<<t.stu.name<<" 学生年龄:"<<t.stu.age<<" 学生分数:"<<t.stu.score<<endl;

    system("pause");

    return 0;

}

结构体做函数参数

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

传递方式:1、值传递  2、地址传递

#include<iostream>

#include<string>

using namespace std;

//定义学生的结构体

struct student

{

    string name;

    int age;

    int score;

};

//1、值传递     形参发生改变,实参不受影响

void printstu1(struct student s)

{

    s.age = 100;

    cout<<"子函数中 姓名:"<<s.name<<" 年龄:"<<s.age<<" 成绩:"<<s.score<<endl;

};

//2、地址传递   实参随形参一起改变

void printstu2(struct student *p)

{

    p->age = 200;

    cout<<"子函数中 姓名:"<<p->name<<" 年龄:"<<p->age<<" 成绩:"<<p->score<<endl;

};

int main()

{

    //结构体做函数参数

    //将学生传入到一个参数中,打印学生的所有信息

    //创建结构体变量

    struct student s;

    s.name = "张三";

    s.age = 13;

    s.score = 86;

    cout<<"姓名:"<<s.name<<" 年龄:"<<s.age<<" 成绩:"<<s.score<<endl;

    printstu1(s);

    printstu2(&s); //传输地址

    cout<<"姓名:"<<s.name<<" 年龄:"<<s.age<<" 成绩:"<<s.score<<endl;

    system("pause");

    return 0;

}

结构体中const的使用场景

作用:用const来防止误操作(限定只读状态,防止修改)

#include<iostream>

#include<string>

using namespace std;

//const 的使用场景

struct student

{

    string name;

    int age;

    int score;

};

//将函数中的形参改为指针,可以减少内存空间,而且不会复制新的副本出来

void printstu(const student *s) //加入const后,一旦有操作就会报错,可以防止我们的误操作

{

    //s->age = 150;   会报错

    cout<<"姓名:"<<s->name<<" 年龄:"<<s->age<<" 成绩:"<<s->score<<endl;

};

int main()

{

    struct student s = {"张三",15,89};

    printstu(&s);

    system("pause");

    return 0;

}

/*void printstu(student s[3])   //值传递

{

    for(int i = 0;i<3;i++)

    {

        cout<<"姓名:"<<s[i].name<<" 年龄:"<<s[i].age<<" 成绩:"<<s[i].score<<endl;

    }



};

int main()

{

    //创建结构变量

    struct student s[3] =

    {

        {"张三",15,89},

        {"李四",16,53},

        {"王五",18,86}

    };

    //通过函数打印结构体变量信息

    printstu(s);

    system("pause");

    return 0;

}*/

结构体案例1

1、学校正在做毕设项目,每名老师带领5名学生,共3名老师,需求如下:

          设计学生和老师的结构体,其中在老师的结构体中,有老师姓名和一个存放5名学生的数组作为成员学生的成员有姓名、成绩,创建数组存放3名老师,通过函数给每个老师及所带学生赋值,最终打印出老师数据以及老师所带的学生数据。

#include <iostream>

#include <string>

#include <ctime>

using namespace std;

//学生的结构体

struct student

{

    //姓名

    string sname;

    //分数

    int score;

};

//老师的结构体定义

struct teacher

{

    //姓名

    string tname;

    //学生数组

    struct student s[5];

};

//给老师和学生赋值的函数

void balabala(struct teacher t[] , int len)

{

    string nameseed = "ABCDE";

    //给老师开始赋值

        for(int i = 0;i<len;i++)

        {

        t[i].tname = "teacher_";

        t[i].tname += nameseed[i];

            //通过循环给每名老师所带的学生赋值

            for(int j = 0;j<5;j++)

            {

                t[i].s[j].sname = "student_";

                t[i].s[j].sname += nameseed[j];

                int random = rand() % 61 + 40;

                t[i].s[j].score = random;

            }   

        }

}

void printInfo(struct teacher t[], int len)

{

    for(int i = 0;i<len;i++)

    {

        cout << "老师的姓名:" << t[i].tname << endl;

        for (int j = 0;j<5;j++)

        {

            cout << "\t学生姓名:" << t[i].s[j].sname <<

                " 考试分数:" << t[i].s[j].score << endl;

        }

    }

}

int main()

{

    //随机数种子

    srand((unsigned int)time(NULL));

    //1、创建3名老师的数组

    struct teacher t[3];

    //2、通过函数给3名老师的信息赋值,并给老师带的学生信息赋值

    int len = sizeof(t) / sizeof(t[0]);

    balabala(t,len);

    //3、打印所有老师及所带的学生信息

    printInfo(t,len);

    system("pause");

    return 0;

}

案例练习2

          设计一个英雄的结构体,包括姓名、年龄、性别;创建结构体数组,数组中存放5名英雄。通过冒泡排序的算法,将数组中的英雄按照年龄进行升序排序,最终打印排序后的结果。

五名英雄信息如下:

{刘备,23,男} {关羽,22,男}

{张飞,20,男} {赵云,21,男} {貂蝉,19,女}

#include<iostream>

#include<string>

using namespace std;

//创建英雄的结构体

struct hero

{

    string name;

    int age;

    string sex;

};

//冒泡排序函数并打印输出

void bala(struct hero san[],int len)

{

    for(int i = 0;i<len-1;i++)

    {

        for(int j = 0;j<len-i-1;j++)

        {

            //如果j下标的元素年龄 大于 j+1下标的元素年龄,交换

            if(san[j].age>san[j+1].age)

            {

                struct hero temp = san[j];

                san[j] = san[j+1];

                san[j+1] = temp;

            }

        }

    }

};

void printall(struct hero san[],int len)

{

    cout<<"按照年龄排序:"<<endl;

    for(int i = 0;i<len;i++)

    {

        cout<<"姓名:"<<san[i].name<<" 年龄:"<<san[i].age<<" 性别:"<<san[i].sex<<endl;

    }

};

int main()

{

    //创建结构体数组

    struct hero san[5] =

    {

        {"刘备",23,"男"},{"关羽",22,"男"},

        {"张飞",20,"男"},{"赵云",21,"男"},

        {"貂蝉",19,"女"}

    };

    int len = sizeof(san)/sizeof(san[0]);

    for(int i = 0;i<5;i++)

    {

        cout<<"姓名:"<<san[i].name<<" 年龄:"<<san[i].age<<" 性别:"<<san[i].sex<<endl;

    }

    bala(san,len);

    printall(san,len);

    system("pause");

    return 0;

}

内存分区模型

  1. 代码区:存放函数体的二进制代码,由操作系统进行管理的
  2. 全局区:存放全局变量、静态变量、常量

  静态变量:在普通变量前加static

  常量:字符串常量、const修饰的常量

       Const修饰的常量:全局、局部

  1. 栈区:由编译器自动分配释放,存放函数的参数值、局部变量等
  2. 堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收

C++在程序运行前分为全局区和代码区

代码区特点是共享和只读

全局区中存放全局变量、静态变量、常量

常量区中存放const修饰的常量和字符串常量

栈区:由编译器自行释放,存放函数的参数值、局部变量等

堆区:利用new关键字,可以将数据开辟到堆区

注:不要返回局部变量的地址,栈区的数据由编译器管理开辟和释放

  •         指针本质也是局部变量,放在栈上,指针保存的数据放在堆区    
  •         野指针:访问一个已销毁或者访问受限的内存区域的指针,野指针不能判断是否为NULL来避免
  •         垂悬指针:指针正常初始化,曾指向一个对象,该对象被销毁了,但是指针未制空,那么就成了悬空指针。
  •         堆区开辟的数据,由程序员手动开辟,手动释放,释放利用delete操作符

引用

本质:变量别名

语法:数据类型 & 别名 = 原名

注:1、引用必须要初始化

                       nt &b; //错误

        2、引用一旦确定,不可改变

#include<iostream>

using namespace std;

int main()

{

   int a = 10;

   int& b = a; //初始化

   int c = 20; //不可更改

   b = c; //赋值操作,不是更改引用

   cout << "a = " << a << endl;

   cout << "b = " << b << endl;

   cout << "c = " << c << endl;

   system("pause");

   return 0;

}

引用的本质:指针常量

#include<iostream>

using namespace std;

void test(const int& a)//防止实参被修改

{

   //int a = 100; 不可被修改

   cout << "a = " << a << endl;

}

int main()

{

   int a = 1000;

   test(a);

   system("pause");

   return 0;

}

函数的默认参数

#include<iostream>

using namespace std;

//函数的默认参数

//如果传入了新数据,就用自己的数据,若没有,则用默认参数

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

//如果函数声明有了默认参数,函数实现就不能有默认参数,声明和实现只能有一个默认参数

int test(int a, int b = 1, int c = 2)

{

   return a + b + c;

}

int main()

{

   int a = 1, b = 2, c = 3;

   cout << test(a, 2) << endl;

   system("pause");

   return 0;

}

函数重载(提高函数复用性)

条件:   1、作用于统一作用域下

              2、函数名称相同

              3、函数参数类型不同,或者个数不同,顺序不同

#include<iostream>

using namespace std;

void func()

{

   cout << "1" << endl;

}

void func(int a)

{

   cout << "1.1" << endl;

}

//函数重载遇到默认参数

void func1(int a, int b = 10)

{

   cout << "2" << endl;

}

void func1(int a)

{

   cout << "2.1" << endl;

}

int main()

{

   int a = 10;

   func(a);

   //func1(a);  出现二义性,报错,尽量避免这种情况出现

   system("pause");

   return 0;

}

类和对象

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

封装的意义: 将属性和行为作为一个整体表现事物 

                       将属性和行为加以权限控制

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

        (行为通常用函数)

#include<iostream>

using namespace std;

//设计一个圆,求圆的周长

const double pai = 3.14;

//class代表设计一个类,类后面紧跟着的就是类名称

class circle

{

   //访问权限

public:

   //属性 半径

   int a;

   //行为 通常用函数

   double  circlelatec()

   {

     return 2 * pai * a;

   }

};

int main()

{

   //通过圆类创建具体的圆

   circle c1;

   //给圆的对象的属性进行赋值

   c1.a = 10;

   //调用函数

   cout << "圆的周长为:" << c1.circlelatec() << endl;

   system("pause");

   return 0;

}

//设计一个学生类,属性有姓名、学号,可以给姓名、学号赋值,可以显示姓名、学号

#include<iostream>

#include<string>

using namespace std;

class student

{

   //访问权限

public:

   //属性

   string name;

   int id;

   //行为

   //函数的声明

   student();//构造函数

   void input();//信息输入函数

   void out();//信息输出函数

};

student::student()

{

   name = "no name";

   id = 0;

}

void student::input()

{

   cout << "姓名:";

   cin >> name;

   cout << "学号:";

   cin >> id;

}

void student::out()

{

   cout << "姓名:" << name << endl;

   cout << "学号:" << id << endl;

}

int main()

{

   char x = '0';

   //创建对象

   student a;

   student b[20];

   cout << "请输入学生信息:" << endl;

   for (int i = 0; x != 'n'; i++)

   {

     cout << i + 1 << "号";

     b[i].input();

     cout << "按下‘n’结束" << endl;

     cin >> x;

   }

   cout << "所有人的信息是:" << endl;

   for (int j = 0; j < 20; j++)

   {

     b[j].out();

   }

   system("pause");

   return 0;

}

继承

 
 

公有public:类内可以访问,类内也可以访问

保护protected:类内可以访问,类外不可以访问

私有private:类内可以访问,类外不可以访问

//继承中的对象模型

#include<iostream>

using namespace std;

class fath

{

public:

   int m_a;

protected:

   int m_b;

private:

   int m_c;

};

class son :public fath

{

public:

   int m_d;

};

//在父类中所有的非静态成员都会被子类继承下来,父类中私有的属性,被编译器隐藏了,因此访问不到

int main()

{

   cout << sizeof(son) << endl;

   system("pause");

   return 0;

}

struct和class的区别

默认的访问权限不同:
           struct默认权限为公有

           Class默认为私有

成员属性设置为私有

优点:   1、可以自己控制读写数据

              2、可以检测数据的有效性

#include<iostream>

using namespace std;

#include<string>

class person

{

public:

   void setname(string name)//可读可写  写

   {

     m_name = name;

   }

   string showname() //读

   {

     return m_name;

   }

   int showage() //只读

   {

     m_age = 18;

     return m_age;

   }

private:

   string m_name;

   int m_age;

   int m_id;

};

int main()

{

   person p;

   p.setname("张三");

   cout << "姓名:" << p.showname() << endl;

   cout << "年龄:" << p.showage() << endl;

   system("pause");

   return 0;

}

例1:封装一个长方体类

#include<iostream>

using namespace std;

class cube

{

public:

   //设置高

   void seth(int h)

   {

     m_h = h;

   }

   //显示高

   int showh()

   {

     return m_h;

   }

   void setl(int l)

   {

     m_l = l;

   }

   int showl()

   {

     return m_l;

   }

   void setw(int w)

   {

     m_w = w;

   }

   int showw()

   {

     return m_w;

   }

   //获取面积

   int s()

   {

     return m_h * m_l * 2 + m_h * m_w * 2 + m_l * m_w * 2;

   }

   //获取体积

   int v()

   {

     return m_h * m_l * m_w;

   }

private:

   int m_h;

   int m_l;

   int m_w;

};

int main()

{

   cube s;

   s.seth(1);

   s.setl(2);

   s.setw(3);

   cout << "长方体面积:" << s.s() << endl;

   cout << "长方体体积:" << s.v() << endl;

   system("pause");

   return 0;

}

例2:判断点与圆的位置关系

要求:创建点与圆类 判断位置换下

#include<iostream>

using namespace std;

class point

{

public:

   int m_x;

   int m_y;

   //函数的声明

   void setx(int x);

   void sety(int y);

   int showx();

   int showy();

};

void point::setx(int x)

{

   m_x = x;

}

int point::showx()

{

   return m_x;

}

void point::sety(int y)

{

   m_y = y;

}

int point::showy()

{

   return m_y;

}

class circle

{

public:

   int m_r;

   point m_center;

   //函数的声明

   void setr(int r);

   void setcenter(point center);

   int showr();

   point showcenter();

};

void circle::setr(int r)

{

   m_r = r;

}

int circle::showr()

{

   return m_r;

}

void circle::setcenter(point center)

{

   m_center = center;

}

point circle::showcenter()

{

   return m_center;

}

void isincir(circle& c, point& p)

{

   //计算两点间距离的平方

   int distence = (c.showcenter().showx() - p.showx()) * (c.showcenter().showx() - p.showx()) +

     (c.showcenter().showy() - p.showy()) * (c.showcenter().showy() - p.showy());

   //计算半径的平方

   int rdistence = c.showr() * c.showr();

   //判断半径与两点间距离的大小

   if (distence == rdistence)

   {

     cout << "点在圆上" << endl;

   }

   else if (distence > rdistence)

   {

     cout << "点在圆外" << endl;

   }

   else

   {

     cout << "点在圆内" << endl;

   }

}

int main()

{

   point p;

   p.setx(10);

   p.sety(10);

   circle c;

   c.setr(10);

   point center;

   center.setx(10);

   center.sety(0);

   c.setcenter(center);

   //判断关系

   isincir(c, p);

   system("pause");

   return 0;

}

构造函数和析构函数

对象的初始化和清理(安全问题):

  1. 一个对象或者变量没有初始状态,对其使用后果是未知的
  2. 使用完一个对象或变量,没有及时清理,也存在安全问题

C++利用构造函数和析构函数解决上述问题,若我们不提供构造和析构,编译器会提供,编译器提供的得构造和析构函数是空实现的。

构造函数:作用于创造对象时为对象的成员赋值,构造函数由编译器自动调用,无需手动调用

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

构造函数语法:  类名(){ }
1、构造函数没有返回值,也不写void

2、函数名称与类名相同

3、构造函数可以有参数,可以发生重载

4、程序在调用对象时候会自动调用构造,无需手动调用,而且只调用一次

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

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

2、函数名称与类名相同,在名称前加 ~ 符号

3、析构函数不可以有参数,不可以发生重载

4、程序在对象对象时会自动调用析构,无需手动调用,而且只调用一次

#include<iostream>

using namespace std;

class person

{

public:

   person()

   {

     cout << "构造函数" << endl;

   }

   ~person()

   {

     cout << "析构函数" << endl;

   }

};

void s()

{

   person p;

}

int main()

{

   person p;

   system("pause");

   return 0;

}

构造函数的分类和调用

两种分类方式:

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

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

三种调用方式:

                        括号法                           显示法                           隐式转换法

e27b4702d4fb4a089094feb0738d1a20.pngf2942a275a5c4d4eb63ab8c67b4b18ae.png

#include<iostream>

using namespace std;

class person

{

public:

   int m_age;

   //无参构造

   person()

   {

     cout << "无参构造" << endl;

   }

   //有参构造

   person(int age)

   {

     m_age = age;

     cout << "有参构造" << endl;

   }

   //拷贝函数

   person(const person &p)

   {

     m_age = p.m_age;

     cout << "123" << endl;

   }

   ~person()

   {

     cout << "析构函数" << endl;

   }

  

};

//调用函数

void d()

{

   //1、括号法

   person p1; //默认构造函数调用(无参)

   person p2(10); //默认构造函数调用(有参)

   person p3(p2); //拷贝函数调用

   //2、显示法

   person p4;

   person p5 = person(10);

   person p6 = person(p2);

   //3、隐式转换法

   person p7 = 10; //相当于写了  person p7 = person(10);  有参函数

   person p8 = p7; //拷贝构造

}

int main()

{

   d();

   system("pause");

   return 0;

}

拷贝构造函数调用时机

  1. 使用一个已经创建完毕的对象来初始化一个新对象
  2. 值传递的方式给函数参数传值
  3. 以值方式返回局部对象
#include<iostream>

using namespace std;

//拷贝构造函数的调用时机

class person

{

public:

  int m_age;

  person()

  {

     cout << "默认构造函数" << endl;

  }

  person(int age)

  {

     m_age = age;

     cout << "有参" << endl;

  }

  person(const person& p)

  {

     cout << "拷贝" << endl;

     m_age = p.m_age;

  }

  ~person()

  {

     cout << "析构函数" << endl;

  }

};

//1、使用一个已经创建完毕的对象来初始化一个新对象

void a()

{

  person p1(10);

  person p2(p1);

  cout << "年龄:" << p2.m_age << endl;

}

//2、值传递的方式给函数参数传值

void dowork(person p)

{



}

void b()

{

  person p;

  dowork(p);

}

//3、值方式返回局部对象

person dowork1()

{

  person p3;

  cout << (int*)&p3 << endl;

  return p3;

}

void c()

{

  person p = dowork1();

  cout << (int*)&p << endl;

}

int main()

{

  a();

  b();

  system("pause");

  return 0;

}

深拷贝和浅拷贝

浅拷贝:简单的赋值操作(编译器帮助进行,无需定义)

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

#include<iostream>

using namespace std;

//深拷贝和浅拷贝

class person

{

public:

   int m_age;

   int* m_hight; // 通过指针将数据开辟到堆区

   person()

   {

     cout << "person默认构造函数的调用" << endl;

   }

   person(int age,int hight)

   {

     m_hight = new int(hight); //通过new关键字将数据开辟到堆区

     m_age = age;

     cout << "person有参构造函数的调用" << endl;

   }

   //自己创建深拷贝,来解决浅拷贝的问题

   person(const person& p)

   {

     cout << "拷贝构造函数调用" << endl;

     //m_hight = p.m_hight; 编译器自动实现

     m_age = p.m_age;

     //深拷贝

     m_hight = new int(*p.m_hight);

   }

   ~person()

   {

     //析构函数 将堆区开辟的数据进行释放操作

     if (m_hight != NULL)

     {

        delete m_hight;

        m_hight = NULL;

     }

     cout << "析构函数的调用" << endl;

   }

};

void test1()

{

   person p1(18,134);

   cout << "年龄:" << p1.m_age << endl;

   cout << "体重;" << *p1.m_hight << endl;

   person p(p1); //浅拷贝

   cout << "年龄:" << p.m_age << endl;

   cout << "体重;" << *p.m_hight << endl;

}

int main()

{

   test1();

   system("pause");

   return 0;

}

总结:如果属性有在堆区开辟的,那么一定要自己去构建拷贝调用函数,防止浅拷贝带来的问题。

初始化列表

语法:构造函数():属性1(值1),属性2(值2)…{ }

#include<iostream>

using namespace std;

//初始化列表

class person

{

public:

   int m_a;

   int m_b;

   int m_c;

   //传统初始化操作

   /*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)

   {



   }

};

void test()

{

   person p(1,2,3);

   cout << p.m_a << " " << p.m_b << " " << p.m_c << endl;

}

int main()

{

   test();

   system("pause");

   return 0;

}

类对象作为类成员

C++类的成员可以是另一个类的对象,称为对象成员

#include<iostream>

#include<string>

using namespace std;

//类对象作为类成员

//当其他类对象作为本类成员,构造时候先构造类对象,再构造自身,析构顺序与之相反

class phone

{

public:

   //手机品牌名称

   string m_pname;

   phone(string pname)

   {

     m_pname = pname;

     cout << "phone的构造函数调用" << endl;

   }

   ~phone()

   {

     cout << "phone析构函数的调用" << endl;

   }

};

class person

{

public:

   string m_name;

   phone m_phone; 

   person(string name, string pname) :m_name(name), m_phone(pname)

   {

     cout << "person构造函数的调用" << endl;

   }

   ~person()

   {

     cout << "person析构函数调用" << endl;

   }

};



void test()

{

   person p("张三", "华为");

   cout << p.m_name << " " << p.m_phone.m_pname << endl;

}



int main()

{

   test();

   system("pause");

   return 0;

}

静态成员

静态成员就是在成员变量和成员函数前加上关键字static

静态成员:

                 静态成员变量:

        所有对象共享一份数据,在编译阶段分配内存,类内申明,类外初始化

#include<iostream>

using namespace std;

//静态成员变量

class perosn

{

public:

  /*1、所有对象共享同一份数据

    2、在编译阶段分配内存

    3、类内声明,类外初始化*/

  static  int m_a;

};

int perosn::m_a = 12;

void test()

{

  /*静态成员变量不属于某个对象,所有对象都共享同一份数据

  因此静态成员有两种访问方式*/

  //1、通过对象进行访问

  perosn p;

  cout << p.m_a << endl;

  /*2、通过类名进行访问

  cout<<perosn::m_a<<endl;  */

}

int main()

{

  test();

  system("pause");

  return 0;

}

             静态成员函数:

   所有对象共享同一个函数,静态成员函数只能访问静态成员变量

#include<iostream>

using namespace std;

class person

{

public:

  static void func()

  {

    m_a = 12;

    cout << "静态成员函数" << endl;

    cout << m_a << endl;

  }

  static int m_a;

};

int person::m_a = 13;

void test()

{

  person p;

  p.func();

}

int main()

{

  test();

  system("pause");

  return 0;

}

this指针概念

this 指针指向被调用的成员函数所属的对象

this 指针隐含在每一个非静态成员函数内,无需定义,直接使用

        用途:在形参和成员变量同名时,可用this指针区分

                   在类的非静态成员函数中返回对象本身,可使用  return *this

 #include<iostream>

using namespace std;

class person

{

public:

person(int age)

{

   //this指针指向被调用的成员函数所属的对象

   this->age = age;

}

person& personaddage(person &p1)//返回本体,需要以引用的方式定义

{

   this->age += p1.age;

   //this指向p2的指针,*this指向p2的对象本体

   return *this;

}

int age;

};

//解决名称冲突

void test0()

{

person p(12);

cout << "p1的年龄:" << p.age << endl;

}

//返回对象本身

void test1()

{

person p1(10);

person p2(10);

//链式编程思想

p1.personaddage(p2).personaddage(p2).personaddage(p2);

cout << "p1 p2年龄和为:" << p1.age << endl;

}

int main()

{

test0();

test1();

system("pause");

return 0;

}

Const修饰成员函数

常函数:1、常函数不可修改成员属性

        2、成员函数声明时加关键字mutable,在常函数中仍可修改

常对象:常对象只能调用常函数

#include<iostream>

using namespace std;

class person

{

public:

   void showperson()const

   {

     //this指针的本质是指针常量 指针的指向是不可修改的

     //const person * const this

     //在成员函数后加const,修饰的是指针指向,使指针的值也不可修改

     this->m_age1 = 1;

     /*this->m_age = 1;

     this = NULL;  this指针不可修改指针的指向 */

   }

   void func()

   {



   }

   int m_age;

   mutable int m_age1; //特殊变量,即使在常函数中也可以修改值  加关键字 mutable

};

void test()

{

   person p;

   p.showperson();

}

//常对象

void test1()

{

   const person p1;

   //p1.m_age = 1;

   p1.m_age1 = 1; //m_age1为特殊值,在常对象、常函数中都可修改

   //常对象只能调用常函数

   p1.showperson();

   //p1.func();    常对象不可调用普通成员函数,因为普通成员函数可以修改属性

}

int main()

{

   test();

   system("pasue");

   return 0;

}

  
友元

3e633b5292534094b90760a64c10c25a.png

友元的关键字为:friend

友元的三种实现:

  1. 全局函数做友元
  2. 类做友元
  3. 成员函数做友元
#include<iostream>

#include<string>

using namespace std;

//建筑类

class buliding

{

    //标明友军,可以访问类中的私有成员

    friend void goodguy(buliding* buliding);

public:

    string m_sittingroom;

    buliding()

    {

         m_sittingroom = "客厅";

         m_bedroom = "卧室";

    }

private:

    string m_bedroom;

};

//全局函数

void goodguy(buliding *buliding)

{

    cout << "1、全局函数正在访问" << buliding->m_sittingroom << endl;

    cout << "1、全局函数正在访问" << buliding->m_bedroom << endl;

}

void test()

{

    buliding buliding;

    goodguy(&buliding);

}

int main()

{

    test();

    system("pause");

    return 0;

}
#include<iostream>

#include<string>

using namespace std;

class Buliding;

class good;

void test();

class good

{

public:

   good();

   void visit();  //让visit函数可以访问buliding中的私有成分

   void visit1(); //让visit1函数无法访问buliding中的私有成分

   Buliding* buliding;

};

class Buliding

{

   friend void good::visit();

public:

   Buliding();

   string sittingroom;

private:

   string bedroom;

};

//类外实现函数

Buliding::Buliding()

{

   sittingroom = "客厅";

   bedroom = "卧室";

}

good::good()

{

   buliding = new Buliding;

}

void good::visit()

{

   cout << "公共:" << buliding->sittingroom << endl;

   cout << "私有:" << buliding->bedroom << endl;

}

void good::visit1()

{

   cout << "公共:" << buliding->sittingroom << endl;

}

void test()

{

   good g;

   g.visit();

   g.visit1();

}

int main()

{

   test();

   system("pause");

   return 0;

}

运算符重载

给运算符重定义,赋予其另一种功能,以适应不同的数据类型

          加法运算符重载

作用:实现两个自定义数据类型相加

#include<iostream>

using namespace std;

//加号运算符重载

//成员函数重载

class person

{

public:

   //成员函数重载+

   //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;

   //}

   int m_a;

   int m_b;

};

    //全局函数重载+

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;

}

void test()

{

   person p1;

   p1.m_a = 10;

   p1.m_b = 10;

   person p2;

   p2.m_a = 10;

   p2.m_b = 10;

   person p3 = p1 + p2;

   cout << p3.m_a << " " << p3.m_b << endl;

}

int main()

{

   test();



   system("pause");

   return 0;

}

                  左移运算符重载

作用:输出自定义类型

#include<iostream>

using namespace std;

//左移运算符重载

class person

{

   //利用友元函数访问私有属性

   friend ostream& operator<<(ostream& cout, person& p);

public:

   person(int a,int b)

   {

     m_a = a;

     m_b = b;

   }

private:

   //利用成员函数重载 左移运算符 p.operator<<(cout) 简化:p<<cout

   //不会利用成员函数重载<<运算符,因为无法实现cout 在左边

   //void operator<<()

   int m_a;

   int m_b;

};

//只能利用全局函数重载  ostream标准的输出流对象

ostream & operator<<(ostream &cout,person &p)

{

   cout << p.m_a << " " << p.m_b;

   return cout;

}

void test()

{

   person p(10, 10);

   cout << p << endl;

}

int main()

{

   test();

   system("pause");

   return 0;

}

总结:重载左移运算符配合友元函数可以实现自定义数据类型

                  递增运算符重载

  63184cd4d0974018af7154428d3d73eb.png
作用:通过递增运算符重载,实现自己的整型数据 

#include<iostream>

using namespace std;

//重载递增运算符

class myint

{

   friend ostream& operator<<(ostream& cout, myint myi);

public:

   myint()

   {

     m_num = 0;

   }

   //重载前置++运算符  返回引用是为了一直对一个数据进行操作

   myint& operator++()

   {

     //先进行++操作

     m_num++;

     //再做自身的返回

     return *this;

   }

   //重载后置++运算符

   myint operator++(int) //int表示占位函数,可以用于区分前置和后置递增

     //返回的是局部对象的引用,局部对象在当前函数执行结束后被系统释放

     //所以后置递增返回值,而不是地址

   {

     //先记录当前结果

     myint temp = *this;

     //后递增

     m_num++;

     //最后将记录结果做返回

     return temp;

   }

private:

   int m_num;

};

ostream& operator<<(ostream& cout, myint myi)

{

   cout << myi.m_num;

   return cout;

}

void test()

{

   myint myi;

   cout << ++(++myi) << endl;

   cout << myi << endl;

}

void test1()

{

   myint myi;

   cout << myi++ << endl; //先输出myi,再进行++操作

   cout << myi << endl; //因此这里的myi为myi++的值

}

int main()

{

   test();

   test1();

   //int a = 0;

   //cout << ++(++a) << endl;

   //cout << a << endl;

   system("pause");

   return 0;

}

赋值运算符重载

C++编译器至少给一个类提供4个函数

  1. 默认构造函数(无参,函数体为空)
  2. 默认析构函数(无参,函数体为空)
  3. 默认拷贝构造函数,对属性进行值拷贝
  4. 赋值运算符 operator = 对属性进行值拷贝
#include<iostream>

using namespace std;

//重载赋值运算符

class person

{

public:

    person(int age)

    {

         m_age = new int(age);  //利用new关键字将数据开辟到堆区,堆区的数据需要由程序员自行释放

    }

    ~person()

    {

         cout << "析构函数" << endl;

         if (m_age != NULL)

         {

             delete m_age; //利用delete关键字,将内存释放

             m_age = NULL;

         }

    }

    person& operator=(person& p)

    {

         //先判断是否有堆区的数据,然后进行释放,再进行深拷贝

         if (m_age != NULL)

         {

             delete m_age;

             m_age = NULL;

         }

         //深拷贝

         m_age = new int(*p.m_age);

         //返回对象本身

         return *this;

    }

    int *m_age;

};

void test()

{

    person p(12);

    person p1(18);

    person p2(13);

    p2 = p1 = p;

    cout << *p.m_age << endl;  // * 为解引用,若无解引用,输出的为地址

    cout << *p1.m_age << endl;

    cout << *p2.m_age << endl;

}

int main()

{

    test();

    system("pause");

    return 0;

}

关系运算符重载

   作用:让两个自定义的数据类型进行对比操作

 #include<iostream>

using namespace std;

class person

{

   friend void test();

public:

   person(string name, int age)

   {

     m_name = name;

     m_age = age;

   }

   bool operator==(person &p)

   {

     if (this->m_name == p.m_name && this->m_age == p.m_age)

     {

        return true;

     }

     else

     {

        return false;

     }

     return this;

   }

   bool operator!=(person& p)

   {

     if (this->m_name != p.m_name && this->m_age != p.m_age)

     {

        return true;

     }

     else

     {

        return false;

     }

   }

private:

   int m_age;

   string m_name;

};

void test()

{

   person p1("Tom", 18);

   person p2("aom", 12);

   cout << p1.m_age << " " << p1.m_name << endl;

   cout << p2.m_age << " " << p2.m_name << endl;

   if (p1  == p2)

   {

     cout << "p1与p2是相等的" << endl;

   }

   else

   {

     cout << "p1和p2是不相等的" << endl;

   }

   if (p1 != p2)

   {

     cout << "p1与p2是不相等的" << endl;

   }

   else

   {

     cout << "p1和p2是相等的" << endl;

   }

}

int main()

{

   test();

   system("pause");

   return 0;

}

函数调用运算符重载

 结束后立即释放,因此匿名函数比非匿名函数更节省空间

469c41c9619545a68c32dafd6945f574.png

#include<iostream>

using namespace std;

//函数运算符重载   打印输出类

class print

{

public:

void operator()(string test)

{

   cout << test << endl;

}

};

void test()

{

print p;

p("hello world");

}

//加法类

class add

{

public:

void operator()(int num1,int num2)

{

   cout << num1 + num2 << endl;

}

};

void test1()

{

add a;

a(1, 2);

}

int main()

{

test();

test1();

system("pause");

return 0;

}

 
继承

继承语法:class 子类 :继承方式 父类

      子类也称派生类,父类也称基类

#include<iostream>

using namespace std;

//普通实现画面

//class java

//{

//public:

// void head()

// {

//    cout << "首页、公开课...." << endl;

// }

// void foot()

// {

//    cout << "帮助中心、交流合作..." << endl;

// }

// void left()

// {

//    cout << "java、c++...." << endl;

// }

// void content()

// {

//    cout << "java视频" << endl;

// }

//};

//class python

//{

//public:

// void head()

// {

//    cout << "首页、公开课...." << endl;

// }

// void foot()

// {

//    cout << "帮助中心、交流合作..." << endl;

// }

// void left()

// {

//    cout << "java、c++...." << endl;

// }

// void content()

// {

//    cout << "python视频" << endl;

// }

//};

//class cpp

//{

//public:

// void head()

// {

//    cout << "首页、公开课...." << endl;

// }

// void foot()

// {

//    cout << "帮助中心、交流合作..." << endl;

// }

// void left()

// {

//    cout << "java、c++...." << endl;

// }

// void content()

// {

//    cout << "c++视频" << endl;

// }

//};

//void test()

//{

// cout << "Java下载视频页面如下:" << endl;

// java j;

// j.head();

// j.foot();

// j.left();

// j.content();

// cout << "------------------------------" << endl;

// cout << "Python下载视频页面如下:" << endl;

// python p;

// p.head();

// p.foot();

// p.left();

// p.content();

// cout << "------------------------------" << endl;

// cout << "C++下载视频页面如下:" << endl;

// cpp c;

// c.head();

// c.foot();

// c.left();

// c.content();

//}

//利用继承实现页面的显示

class basepage

{

public:

void head()

{

   cout << "首页、公开课...." << endl;

}

void foot()

{

   cout << "帮助中心、交流合作..." << endl;

}

void left()

{

   cout << "java、c++...." << endl;

}

};

class java :public basepage

{

public:

void content()

{

   cout << "java视频" << endl;

}

};

class python :public basepage

{

public:

void content()

{

   cout << "python视频" << endl;

}

};

class cpp :public basepage

{

public:

void content()

{

   cout << "c++视频" << endl;

}

};

void test()

{

cout << "————————————" << endl;

cout << "java页面如下:" << endl;

java j;

j.head();

j.foot();

j.left();

j.content();

cout << "————————————" << endl;

cout << "python页面如下:" << endl;

python p;

p.head();

p.foot();

p.left();

p.content();

cout << "————————————" << endl;

cout << "cpp页面如下:" << endl;

cpp c;

c.head();

c.foot();

c.left();

c.content();

}

int main()

{

test();

system("pause");

return 0;

}

继承方式

语法:class 子类 :继承方式 父类

继承方式分为:     public 公开继承

                              protect 保护继承

                              private 私有继承

529c37960d4743e5bfa0114326040ad7.png

继承中的对象模型

父类中的所有成员都会被子类继承下来,其中私有属性被编译器隐藏起来,因此访问不到

继承中构造和析构顺序

子类继承父类后,创建子类对象,也会调用父类的构造函数

继承中构造与析构的数据: 先构造父类,再构造子类,析构的顺序与构造相反

继承同名成员处理方式

 访问子类同名数据,直接访问

 访问父类同名数据,需要加作用域

 如果子类中出现了与父类中同名的成员函数,编译器会自动隐藏掉父类中所有的同名成员函数

#include<iostream>

using namespace std;

class person

{

public:

   int m_age;

   person()

   {

     m_age = 1;

   }

   void func()

   {

     cout << "父类成员函数" << endl;

   }

};

class son :public person

{

public:

   int m_age;

   son()

   {

     m_age = 2;

   }

   void func()

   {

     cout << "子类成员函数" << endl;

   }

};

//同名属性

void test()

{

   son s;

   cout << s.m_age << endl;

   //通过子类对象访问父类中的属性,需要加作用域

   cout << s.person::m_age << endl;

}

//同名函数

void test1()

{

   son s1;

   s1.func();

   s1.person::func();

}

int main()

{

   test();

   test1();

   system("pause");

   return 0;

}

继承同名静态成员处理方式

 访问子类同名成员,直接访问

 访问父类同名成员,需要作用域

#include<iostream>

using namespace std;

//静态成员变量  所有对象共享一份数据,在编译阶段分配内存,类内申明,类外初始化

class person

{

public:

   static int m_a;

   static void func()

   {

     cout << "父类成员函数" << endl;

   }

};

int person::m_a = 1;

class son :public person

{

public:

   static int m_a;

   static void func()

   {

     cout << "子类成员函数" << endl;

   }

};

int son::m_a = 2;

//同名静态成员属性

void test()

{

   son s;

   //静态成员属性有两种访问方式

   //1 通过对象

   cout << s.m_a << endl;

   cout << s.person::m_a << endl;

   //2 通过类名

   cout << son::m_a << endl;

   cout << son::person::m_a << endl;

   //同名静态成员函数

   //1 通过对象

   s.func();

   s.person::func();

   //2 通过类名

   son::func();

   son::person::func();

}

int main()

{

   test();

   system("pause");

   return 0;

}

多继承语法

C++允许一个类继承多个类

语法:class 子类 :继承方式 父类1,继承方式 父类2...

多继承可能会导致父类中有同名成员出现,需要加作用域区分

#include<iostream>

using namespace std;

class person

{

public:

   int m_a;

   person()

   {

     m_a = 1;

   }

};

class person1

{

public:

   int m_b;

   person1()

   {

     m_b = 2;

   }

};

class son :public person, public person1

{

public:

   int m_c, m_d;

   son()

   {

     m_c = 3;

     m_d = 4;

   }

};

void test()

{

   son s;

   cout << s.m_c << " " << s.m_d << endl;

   cout << s.person::m_a << endl;

   cout << s.person1::m_b << endl;

}

int main()

{

   test();

   system("pause");

   return 0;

}

菱形继承

概念:两个派生类继承一个基类,又有某个类同时继承这两个派生类

#include<iostream>

using namespace std;

class animal

{

public:

int m_age;

};

//利用虚继承解决菱形继承的问题 在继承之前加关键字 virtual

//animal类称为虚基类

class sheep :virtual public animal

{



};

class tuo :virtual public animal

{



};

class stuo :public sheep, public tuo

{



};

void test()

{

stuo st;

st.sheep::m_age = 1;

st.tuo::m_age = 2;

//当菱形继承,两个父类具有相同的数据,需要加作用域才能区分

//菱形继承导致数据有两份,资源浪费

cout << st.sheep::m_age << endl;

cout << st.tuo::m_age << endl;

cout << st.m_age << endl;

}

int main()

{

test();

system("pause");

return 0;

}

多态

 多态分类:

        静态多态:函数重载和运算符重载属于静态多态,复用函数名

        动态多态:派生类和虚函数实现运行多态

 静态多态和动态多态区别;

          静态多态的函数地址早绑定  编译阶段确定函数地址

          动态多态的函数地址晚绑定  运行阶段确定函数地址

        (不管什么类型的指针都占4字节)

#include<iostream>

using namespace std;

class animal

{

public:

   //虚函数

   virtual 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 test()

{

   cat c;

   dospeak(c);

   dog d;

   dospeak(d);

}

int main()

{

   test();

   system("pause");

   return 0;

}

多态优点:

  1. 代码组织结构清晰
  2. 可读性强
  3. 利于前期、后期的扩展维护

案例  计算器类

分别利用 普通写法 和 多态技术 设计实现两个操作数进行运算的计算器类

#include<iostream>

#include<string>

using namespace std;

//普通写法

class calculator

{

public:

   int m_num1;

   int m_num2;

   int getresylt(string oper)

   {

     if (oper == "+")

     {

        return m_num1 + m_num2;

     }

     else if (oper == "-")

     {

        if (m_num1 > m_num2)

        {

           return m_num1 - m_num2;

        }

        else

           return m_num2 - m_num1;

     }

     else if (oper == "*")

     {

        return m_num1 * m_num2;

     }

   }

};

void test()

{

   calculator c;

   c.m_num1 = 4;

   c.m_num2 = 2;

   cout << c.m_num1 << "-" << c.m_num2 << "=" << c.getresylt("-") << endl;

}

//利用多态实现计算器

//实现计算器抽象函数

class calculator1

{

public:

   int m_num1;

   int m_num2;

   virtual int getresult() = 0

   {

     return 0;

   }

};

//加法

class add :public calculator1

{

public:

   int getresult()

   {

     return m_num1 + m_num2;

   }

};

//减法

class jian :public calculator1

{

public:

   int getresult()

   {

     return m_num1 - m_num2;

   }

};

//乘法

class chen :public calculator1

{

public:

   int getresult()

   {

     return m_num1 * m_num2;

   }

};

void test1()

{

   calculator1* a = new add;

   a->m_num1 = 21;

   a->m_num2 = 12;

   cout << a->getresult() << endl;

   delete a; //用完后销毁

   calculator1* j = new jian;

   j->m_num1 = 21;

   j->m_num2 = 12;

   cout << j->getresult() << endl;

   delete j;

   calculator1* c = new chen;

   c->m_num1 = 21;

   c->m_num2 = 12;

   cout << c->getresult() << endl;

   delete c;

}

int main()

{

   test();

   test1();

   system("pause");

   return 0;

}

纯虚函数和抽象类

        在多态中,通常父类中虚函数的实现是没有意义的,主要是调用子类中重写的内容,因此可以将虚函数改写为纯虚函数,当类中有了纯虚函数,这个类称为抽象类

纯虚函数语法:

        virtual 返回值类型 函数名 (参数列表)=0;

抽象类特点:

        无法实例化对象

        子类必须重写抽象类中的纯虚函数,否则子类也为抽象类

#include<iostream>

using namespace std;

class base

{

public:

   //纯虚函数

   virtual void func() = 0;

};

class son :public base

{

public:

   virtual void func()

   {

     cout << "1" << endl;

   }

};

class son1 :public base

{

public:

   virtual void func()

   {

     cout << "2" << endl;

   }

};

void test()

{

   //抽象类不允许实例化,无论开辟在堆区还是栈区

   //new calculator;

   //calculator c;

   son s;

   s.func();

   son1 s1;

   s1.func();

}

int main()

{

   test();

   system("pause");

   return 0;

}

虚析构和纯虚析构

共性:

     可以解决父类指针释放子类对象

     都需要有具体的函数实现

区别:

     如果是纯虚析构,该类为抽象类,无法实例化对象

虚析构语法: virtual ~类名(){}

纯虚析构语法:virtual ~类名()= 0;

#include<iostream>

#include<string>  

using namespace std;

class animal

{

public:

   animal()

   {

     cout << "animal构造函数调用" << endl;

   }

   //虚析构

   //virtual ~animal()

   //{

   // cout << "animal析构函数调用" << endl;

   //}

   //纯虚析构需要声明,也休息需要实现

   //有了纯虚析构后,这个类也属于抽象类,无法实例化对象

   virtual ~animal() = 0;

   //纯虚函数

   virtual void speak() = 0;

};

animal::~animal()

{

   cout << "纯虚析构" << endl;

}

class cat :public animal

{

public:

   string* m_name;

   cat()

   {

     cout << "cat构造函数调用" << endl;

   }

   cat(string name)

   {

     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;

     }

   }

};

void test()

{

   animal* animal = new cat("Tom");

   animal->speak();

   //父类指针析构的时候 不会调用子类中析构函数,导致子类中如果有堆区属性,会出现内存泄漏 

   delete animal;

}

int main()

{

   test();

   system("pause");

   return 0;

}

文件操作

         程序运行时产生的数据都是临时数据,程序一旦运行结束就会被释放,通过文件可以将数据持久化

         C++中对文件操作需要加头文件<fstream>

  文件类型: 

  1. 文本文件 文件以ASCII码形式存储于计算机中
  2. 二进制文件 文件以二进制形式存储于计算机中,用户一般不能直接读懂他

操作文件的三大类:

  1. ofstream :写操作
  2. ifstream :读操作
  3. fstream :读写操作

文本文件

写文件

  1. 包含头文件  #include<fstream>
  2. 创建流对象  ofstream ofs;
  3. 打开文件  ofs.open(“文件路径”,打开方式);
  4. 写数据   ofs<<”写入的数据”;
  5. 关闭文件  ofs.close();

33245b5cbe9446fb8aec43103190eba9.png
注:文件打开方式可以配合使用,利用 | 操作符

3423869f99a647649fb03f3b5b612556.png

读文件

读文件步骤:

  1. 包含头文件  include<fstream>
  2. 创建流对象  ifstream ifs;
  3. 打开文件并判断文件是否打开成功 ifs .open(“文件路径”,打开方式);
  4. 读数据  四种方式读取
  5. 关闭文件  ifs.close();
#include<iostream>

#include<string>

#include<fstream>

using namespace std;

void test()

{

    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;

    //}

    //第二种

    //char buf[1024] = { 0 };

    //while (ifs.getline(buf, sizeof(buf)))

    //{

    //  cout << buf << endl;

    //}

    //第三种

    //string buf;

    //while ( getline(ifs,buf))   

    //{

    //  cout << buf << endl;

    //}

    //第四种

    char c;

    while ((c = ifs.get()) != EOF) //EOF  end of file

    {

         cout << c << endl;

    }

    ifs.close();

}

int main()

{

    test();

    system("pause");

    return 0;

}

二进制文件

以二进制方式对文件进行读写操作

打开方式要指定为 ios:: binary

写文件

二进制方式写文件主要利用流对象调用成员函数write

  函数原型:ostream& write(const char*buffer,int len);

buffer 指向内存中的一段存储空间

len是读写的字符数

步骤:

     1. 包含头文件 #include<fstream>

     2.创建输出流对象

 ofstream ofs("person.txt", ios::out | ios::binary);

     3.打开文件

ofs.open("person.txt", ios::out | ios::binary);

  或者   person p = { "张三",18 };

     4.写文件   ofs.write((const char*)&p, sizeof(p));

     5.关闭文件

#include<iostream>

#include<fstream>

using namespace std;

class person

{

public:

    char m_name[64];

    int m_age;

};

void test()

{

    ofstream ofs("person.txt", ios::out | ios::binary);

    //打开文件

    //ofs.open("person.txt", ios::out | ios::binary);

    person p = { "张三",18 };

    ofs.write((const char*)&p, sizeof(p));

    ofs.close();



}

int main()

{

    test();

    system("pause");

    return 0;

}

读文件

二进制方式写文件主要利用流对象调用成员函数write

  函数原型:istream& read(char *buffer,int len);

buffer 指向内存中的一段存储空间

len是读写的字符数

  1. 包含头文件
  2. 创建输出流对象
  3. 打开文件
  4. 写文件
  5. 关闭文件
#include<iostream>

#include<fstream>

using namespace std;

class person

{

public:

    char m_name[64];

    int m_age;

};

void test()

{

    ifstream ifs("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;

    ifs.close();

}

int main()

{

    test();

    system("pause");

    return 0;

}

输出两位数字,当不足两位时,用0补齐

   需要包含头文件 #include<iomanip>

{

    int a;

    cin >> a;

    cout << setw(2) << setfill('0') << a << endl;

}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值