c++学习

  1. c++学习——By Xie
    1. VS使用技巧
    2. sizeof关键字
    3. float 单精度浮点型
    4. 字符型
    5. 转义字符
    6. 字符串
    7. 布尔型
    8. 除法
    9. 取模(取余)运算
    10. 递增
    11. 逻辑运算符
    12. 三目运算符
    13. switch语句
    14. rand( )生成伪随机整数
    15. srand( )生成真随机数
    16. 取出各位上的数字
    17. 指数函数
    18. for循环的省略
    19. 循环嵌套
    20. 一维数组
    21. 删除数组中的一个元素
    22. 求数组元素个数
    23. 数组前后依次交换元素值
    24. 冒泡排序
    25. 数组作为参数传递给函数
    26. 二维数组名称
    27. 二维数组加法
    28. 字符串数组
    29. 函数的参数传递
    30. 函数分文件编写
    31. 指针
    32. 指针常量和常量指针
    33. 值传递
    34. 地址传递
    35. 指针+冒泡排序(升序)
    36. 结构体
    37. 结构体数组
    38. 结构体指针
    39. 结构体嵌套
    40. 结构体数组嵌套
    41. 根据某项元素对结构体数组排序
    42. 无参数调用
    43. 实例——通讯录管理系统
    44. 变量(常量)都在哪
    45. 堆区
    46. 堆区创建数组
    47. 引用
    48. 引用做函数参数(形参)
    49. 引用做返回值
    50. 常量引用
    51. 函数默认参数
    52. 类和结构体
    53. 类成员的访问权限
    54. 中途退出函数
    55. 成员函数和全局函数
    56. 类的嵌套
    57. 分文件编写
    58. 构造函数什么时候被调用
    59. 析构函数执行堆区数据的释放
    60. 浅拷贝的问题
    61. 深拷贝解决堆区重复释放的问题
    62. 初始化列表
    63. 静态成员变量
    64. 静态成员函数
    65. 只有非静态成员变量属于类的对象上
    66. 成员变量和形参名称冲突 this指针
    67. *this返回该对象
    68. this 指针本质是指针常量
    69. 成员函数后加const 常函数
    70. 构造和析构函数上不允许使用类型限定符(如const)
    71. 友元(可以访问类中的私有成员)
      1. 全局函数做友元
      2. 类做友元
      3. 成员函数做友元
    72. 运算符重载(加法)
    73. 运算符重载(左移运算符)
    74. 编译器默认提供的类的函数
    75. 运算符重载(赋值运算)
    76. 继承
    77. 继承方式
    78. 利用开发人员命令提示工具查看对象模型
    79. 子类中同名属性的访问
    80. 多继承
    81. 父类的引用指向子类的对象
    82. 动态多态(父类函数前加virtual)

c++学习——By Xie

以下均为学习b站黑马程序员C++所做笔记,以及简单的学习心得
黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难

VS使用技巧

注释: 先CTRL+K,然后CTRL+C 或者加//

取消注释: 先CTRL+K,然后CTRL+U 或者删除//

调试:F5

单步执行:F10

设置或者删除断点:F9

查找:CTRL+Shift+F

跳转到变量/函数的定义:F12

system("pause")   //显示按任意键继续
system("cls")     //清屏

程序执行到return,会直接跳出该函数

sizeof关键字

sizeof(数据类型/变量名)

int arr[10]={、、、};
int a= sizeof(arr)/sizeof(arr[0]);     //常用来求数组元素个数

float 单精度浮点型

float f1 = 3.14f; //常在末尾加上f,表示单精度
double f2 = 3.14; //在double中常省略

字符型

字符型变量用于显示单个字符

char ch = 'a'; //单引号中只能有一个字母

查看对应的ASCII码值

cout << (int)ch << endl; //强制类型转换
//A——65;a——97

转义字符

\n  换行
\t  水平制表符      和前面的总共构成8个空格,整齐地输出后面的内容
\\  反斜杠字符

字符串

char str[] = "hello world";
string str2 = "hello world"; //两种创建方式    第二种方式要加头文件 #include <string>

布尔型

/*
true  (本质是数字1)
false (本质是数字0)
*/
bool flag = true

除法

两个整数相除,结果依然为整数,直接舍弃小数(没有四舍五入)

int a = 10;
int b = 20;
cout << a/b << endl //结果为0

double d1 = 0.5;
double d2 = 0.22;
cout << d1/d2 << endl;   //2.27273

取模(取余)运算

%
//小数不能做取模运算

递增

int a1 =10;
int a2 = ++a1 * 10; //前置递增,先让变量+1,然后进行表达式的计算   a1=11,a2=110
int b1 = 10;
int b2 = b1++ *10; //后置递增,先进行表达式的计算,再让变量+1   b1=11,b2=100

逻辑运算符

// !非    &&与   ||或

三目运算符

int a=10;
int b=100;
int c=0;
c = ( a<b ? a:b); //将较小值赋值给c

//三目运算符返回的是变量,可以继续赋值
(a<b ? a:b) = 100;   //a=100

switch语句

switch(表达式(变量)  字符型/整型)
{
case1:
case2:
    、、、;  //1和2执行相同的语句
    break;  //没有break,会一直执行后面的语句
、、、
default:
    、、、;  //没有对应的case则执行default

}

rand( )生成伪随机整数

//通用公式: a + rand()% n,a为起始整数,n为能取到的整数个数
/*例如:[1,100]生成随机数:1+rand()%100;
       (1,100]生成随机数:2+rand()%99;
       (1,100)生成随机数:2+rand()%98;

srand( )生成真随机数

//根据当前系统时间生成随机数
#include <ctime>

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

int a = 1+rand()%100;

取出各位上的数字

/*从多位数(例如:n=2456)取出各个位数上的数字
个位:对10取模   int a = n%10;
最高位:除以10的位数-1次方   int b = n/1000;
其他位:除以10的对应次方,再对10取模  取出十位数字: int c = n/10%10;
                                取出百位数字: int d = n/100%10;  间接变成取出个位数字
 */                

指数函数

pow(10.0,3);   //10的3次方`

for循环的省略

//输出0到9所有整数
int i = 0;    
for(; ; ;)
{
    if(i>9)
    {
        break;
    }
    、、、;
    i++;
}

for ( 0int i=0; 1 i<10; 3 i++)
{
2、、、;
} //执行顺序为0 1 2 3 1 2 3……..

循环嵌套

难点是在循环条件的书写,循环嵌套需要做的大体都是一个方形(可能不完整),行用 i 来控制,列用 j 来控制,且每一次 j 循环时 i 为定值,for( ) 循环常用计算需要循环的次数来确定循环条件,特别需要注意 j 关于 i 的通式的书写。

一维数组

//三种定义方式
/*     数组类型 数组名[数组长度];    int a[4];
    数组类型 数组名[数组长度] = {、、、}; int a[4]={1,2,3,4};
    数组类型 数组名[] ={、、、};   int a[]={1,2,3,4};

数组中每个元素类型相同
数组名是首元素的地址,是个常量
*/

int arr[5]= {10,20,30,40,50};
cout << arr<<endl;     //输出为第一个元素地址   等同于 cout<< &arr[0] <<endl;
cout<<(int)arr<<endl;  //以十进制输出

删除数组中的一个元素

//遍历数组,如果某个元素和输入的相同,则删除该元素。可以分成两部分,第一个函数实现查找功能,变量a返回该元素在数组中的序号,没找到则返回-1
//实现删除功能的函数接收返回变量,删除可以用后一个元素覆盖前一个来实现,for循环变量i从a开始到元素数(或者元素数-1)
//最后数组元素数-1
int is_exist(int* arr,int len)
{
    for (int i = 0; i < len; i++)
    {
        if (arr[i] == 6)
        {
            return i;
        }

    }
    return -1;
}   //一定要在for循环遍历整个数组发现没有该值后,再return -1

求数组元素个数

int arr[]={1,2,3,4,5};
int a = sizeof(arr)/sizeof(arr[0]);

数组前后依次交换元素值

//从下标的角度思考,下标来移动,循环条件为 start < end
int arr[5]={1,2,3,4,5};
int start =0; //首下标
int end = sizeof(arr)/sizeof(arr[0])-1; //尾下标
int a = 0;   //存储中间变量
// 、、、、;

冒泡排序

//6个数升序排列,进行5轮(外层循环 i=0,1,2,3,4),每轮比较的次数n-i-1 (j的表达式)
//输入回车开始排序
#include<iostream>
#include<string>
using namespace std;

void maopao(int* p, int len)       //冒泡排序
{
    for (int i = 0; i < len - 1; i++)
    {
        for (int j = 0; j < len - i - 1; j++)
        {
            if (p[j] < p[j + 1])
            {
                int a = p[j];
                p[j] = p[j + 1];
                p[j + 1] = a;
            }
        }
    }
}
int main()
{
    int i = 0;
    int arr[20]  ;            //预先指定数组大小
    while (cin.peek() != '\n')         //键入回车跳出循环
    {
        cin >> arr[i];
        i++;
    }
    int len = i;
    cout << i<<endl;
    maopao(arr, len);
    for (int j = 0; j < len; j++)
    {
        cout << arr[j] << " ";
    }
    cout << endl;
    system("pause");
    return 0;
}

数组作为参数传递给函数

#include<iostream>
#include<string>
using namespace std;

void aaa(int arr[], int len)       //第一种方式 值传递
{
    for (int i = 0; i < len; i++)
    {
        cout << arr[i]<<" ";
    }
    cout << endl;
}
int main()
{
    int arr[] = { 1,2,3,4,5 };
    int len = sizeof(arr) / sizeof(arr[0]);
    aaa(arr, len);

    system("pause");
    return 0;
}

#include<iostream>
#include<string>
using namespace std;

void aaa(int *arr, int len)     //第二种方式 地址传递
{
    for (int i = 0; i < len; i++)
    {
        cout << arr[i]<<" ";
    }
    cout << endl;
}
int main()
{
    int arr[] = { 1,2,3,4,5 };
    int len = sizeof(arr) / sizeof(arr[0]);
    aaa(arr, len);

    system("pause");
    return 0;
}

二维数组名称

//查看内存空间
int arr[2][3]= {{1,2,3},{4,5,6}}
cout << sizeof(arr) <<endl;    //数组占用的总内存空间
cout << sizeof(arr[0]) << endl; //第一行所占内存空间

cout << sizeof(arr)/sizeof(arr[0]);   //二维数组行数
cout << sizeof(arr[0])/sizeof([0][0]); //二维数组列数

//首元素地址
cout << (int)arr <<endl; //数组首地址
cout << (int)arr[0] <<endl; //第一行首地址
cout << &(int)arr[0][0] << endl; //第一个元素首地址

二维数组加法

做加法时,不要用arr[i] [j]+arr[i] [j+1],而是

int sum =0;//定义一个变量作为和
for(int i=0;i<、、、;i++)
{
    for(int j=0;j<、、、;j++)
    {
        sum +=arr[i][j];
    }
}

字符串数组

数组的每一个元素为一个字符串,且不要求长度相同

string arr[3]={"张三","李四","王五"};

函数的参数传递

void test(int a,int b)        //形参接收实参时,int a=c,int b=d;
{
    cout<<a+b<<endl;
}

int main()
{
    int c=10;
    int d=20;
    test(c,d);
    system("pause");
    return 0;
}

函数分文件编写

1、创建 .h 的头文件,在其中写函数声明

2、创建 .cpp 的源文件,在其中写函数的定义

.h文件

#include<iostream>
using namespace std;
void swap(int a, int b);  //函数声明

.cpp文件

#include "swap.h"

void swap(int a, int b)         //函数定义
{
    int c = a;
    a = b;
    b = c;
    cout << "a的值为" << a << endl;
    cout << "b的值为" << b << endl;

}

在主.cpp文件中再加上#include “swap.h” ,即可调用函数

指针

int a=10;     //整型变量要定义整型
int * p = &a;  //p中存的是a的地址
*p = 100;   //解引用,修改指针所指向的内存中的数据     a=100;
//指针也是一种数据类型,表示为int *、float *等,变量名为p,和整型、字符型、字符串一样。sizeof(int *),sizeof(p)。

指针常量和常量指针

const int * p = &a;  //常量指针    与int const *p = &a完全相同
*p =10; //错误    值只能读取,不能修改,防止误操作
p = &b; //正确
const struct student *s;
s->age = 18; //错误,结构体变量中的值不能修改


int * const p = &a;  //指针常量
p = &a; //错误
*p = 10; //正确

值传递

形参的改变不影响实参的值

地址传递

用指针接收变量的地址,修改以后值会发生改变

结构体作为函数参数时,地址传递以指针来接收有利于减少内存空间

指针+冒泡排序(升序)

#include<iostream>
#include<string>
using namespace std;


void swap(int* p,int N)
{
    int* p2 = p;
    for (int i = 0; i < N - 1; i++)
    {
        for (int j = 0; j < N - i-1; j++)
        {
            if (*p2 > * (p2 + 1))
            {
                int c = *p2;
                *p2 = *(p2 + 1);
                *(p2 + 1) = c;
            }
            p2++;
        }
        p2 =p;
    }
}

int main()
{
    int arr[] = { 4,3,1,2,8,7,10,9,5,6 };
    int N = sizeof(arr) / sizeof(arr[0]);    //数组长度
    swap(arr,N);
    for (int k = 0; k < N; k++)
    {
        cout << arr[k]<<" "<<endl;
    }
    system("pause");
    return 0;

}




//指针的两种访问数组值的方式
int *p =arr;
cout << p[2];

int *p =arr;
cout << *(p+2);     //且这两种方式使用后并不改变 p 指向首地址


#include<iostream>
#include<string>
using namespace std;


void swap(int* p,int N)
{
    for (int i = 0; i < N - 1; i++)
    {
        for (int j = 0; j < N - i-1; j++)
        {
            if (p[j] >  p[j+1])
            {
                int c = p[j];
                p[j] = p[j + 1];
                p[j + 1] = c;
            }
        }
    }
}

int main()
{
    int arr[] = { 4,3,1,2,8,7,10,9,5,6 };
    int N = sizeof(arr) / sizeof(arr[0]);
    swap(arr,N);
    for (int k = 0; k < N; k++)
    {
        cout << arr[k]<<" "<<endl;
    }
    system("pause");
    return 0;

}

结构体

struct student
{
    string name;    //姓名
    int age;        //年龄
    int score;        //分数
};    //结构体定义   定义时struct关键字不可省略    定义好之后类似于一个数据类型,后面跟变量名可以直接赋值



//结构体变量创建  struct关键字可省略
student s1;
s1.name = "lalala";
s1.age = 16;
s1.score = 87;

struct student s2={"lalalala", 17, 98};

结构体数组

结构体定义没有区别,变量名变成了一个数组名,数组中的每个元素类型是一个结构体

//创建结构体数组

struct student arr[3]=
{
    {"张三",16,90},
    {"李四",18,70},
    {"王五",19,80}
};
arr[0].age =20;    //仍用变量名. 来访问,用for循环来遍历

结构体指针

结构体定义没有区别

//结构体变量创建
struct student s ={"张三", 17, 90};
struct student *p = &s;

cout << "姓名:"<< p->name << endl;

结构体嵌套

//定义
struct student 
{
    string name;
    int age;
    int score;
}
struct teacher
{
    int id;
    string name;
    struct student stu;
}


//创建变量
struct teacher t;
t.id = 1000;
t.name = "啦啦啦";
t.stu.name ="哦哦哦";
t.stu.age = 17;
t.stu.score =90;

结构体数组嵌套

三个老师每个人带三个学生

#include<iostream>
#include<string>
using namespace std;


struct student
{
    string name;    //姓名
    int score;        //分数
};

struct teacher
{
    string name;
    struct student arr[3];
};


int main()
{
    struct teacher arr1[3];     //难点
    for (int k = 0; k < 3; k++)
    {
        cout << "请输入第"<<k+1<<"个老师姓名:" << endl;
        cin >> arr1[k].name;
        for(int i=0;i<3;i++)
        {
            cout << "请输入他第" << i + 1 << "个学生的姓名" << endl;
            cin >> arr1[k].arr[i].name;
            cout << "请输入他第" << i + 1 << "个学生的成绩" << endl;
            cin >> arr1[k].arr[i].score;
        }

    }

    for (int j = 0; j < 3; j++)
    {
        cout << "第" << j + 1 << "个老师是:" << arr1[j].name << endl;
        for (int b = 0; b < 3;b++)
        {
            cout << "他的第" << b + 1 << "个学生是:" <<arr1[j].arr[b].name<< "  " 
            << "成绩为:" << arr1[j].arr[b].score << endl;
        }

    }

    system("pause");
    return 0;

}

根据某项元素对结构体数组排序

#include<iostream>
#include<string>
using namespace std;

struct hero
{
    string name;
    int age;
    string gender;
};

void bubblesort(hero *arr, int len)       //按年龄对英雄排序
{
    for (int i = 0; i < len-1; i++)
        {
            for (int j = 0; j < len-1 - i; j++)
            {
                if (arr[j].age > arr[j + 1].age)
                {
                    hero a = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = a;
                }
            }
        }
    for (int k = 0; k < 5; k++)
    {
        cout << "姓名:" << arr[k].name << " " << "年龄" <<
    arr[k].age << " " << "性别" << arr[k].gender << endl;
    }
}

int main()
{
    struct hero arr[] =
    {
        {"刘备",23,"男"},
        {"关羽",22,"男"},
        {"张飞",20,"男"},
        {"赵云",21,"男"},
        {"貂蝉",19,"女"}
    };           //五个数冒泡排序
    int len = sizeof(arr) / sizeof(arr[0]);
    bubblesort(arr, len);


    system("pause");
    return 0;

}

无参数调用

void showMenu()
{
    cout << "1、添加联系人" << endl;
    cout << "2、显示联系人" << endl;
    cout << "3、删除联系人" << endl;
    cout << "4、查找联系人" << endl;
    cout << "5、修改联系人" << endl;
    cout << "6、清空联系人" << endl;
    cout << "0、退出该系统" << endl;
}

int main()
{
    showMenu();        //括号不能省略
    system("pause");
    return 0;
}

实例——通讯录管理系统

#include<iostream>
using namespace std;


struct aaa           //联系人结构体
{
    string name;
    string sex;
    int age;
    string phonenumber;
    string address;
};

struct bbb        //通讯录结构体
{
    struct aaa arr[1000];
    int size;    //当前通讯录中人员个数     
};

void showMenu()
{
    cout << "1、添加联系人" << endl;
    cout << "2、显示联系人" << endl;
    cout << "3、删除联系人" << endl;
    cout << "4、查找联系人" << endl;
    cout << "5、修改联系人" << endl;
    cout << "6、清空联系人" << endl;
    cout << "0、退出该系统" << endl;
}

void add_people(bbb *t)
{
    int z = t->size;
    cout << "请输入姓名:" << endl;
    cin >> t->arr[z].name;
    cout << "请输入性别:" << endl;
    cin >> t->arr[z].sex;
    cout << "请输入年龄:"<<endl;
    cin >> t->arr[z].age;
    cout << "请输入电话:" << endl;
    cin >> t->arr[z].phonenumber;
    cout << "请输入地址:" << endl;
    cin >> t->arr[z].address;
    t->size++;

}

void show_people(bbb t)
{
    if (t.size == 0)
    {
        cout << "当前联系人为空" << endl;

    }
    else
    {
        for (int i = 0; i < t.size; i++)
        {
            cout << "姓名:" << t.arr[i].name << " " << "性别:" << t.arr[i].sex << " " << "年龄:" << t.arr[i].age
                << " " << "电话:" << t.arr[i].phonenumber << " " << "地址:" << t.arr[i].address << endl;
        }
    }
}

int is_exist(bbb* t, string name)
{
    int i = 0;
    for (; i < t->size; i++)
    {
        if (t->arr[i].name == name)
        {
            return i;
        }
    }
    return -1;

}       //多个功能都涉及到查找,返回数组元素下标

void delete_people(bbb* t)
{
    string name;
    cout << "请输入想要删除的联系人姓名:";
    cin >> name;
    int a = is_exist(t, name);
    if (a == -1)
    {
        cout << "查无此人!" << endl;
    }
    else
    {
        for (int i = a; i < t->size; i++)
        {
            t->arr[i] = t->arr[i + 1];

        }
        t->size--;
    }
}
void find_people(bbb *t)
{
    string name;
    cout << "请输入想查找的联系人:" << endl;
    cin >> name;
    int a = is_exist(t, name);
    if (a == -1)
    {
        cout << "查无此人!" << endl;
    }
    else
    {
        cout<<"姓名:"<<t->arr[a].name<<" " << "性别:" << t->arr[a].sex << " " << "年龄:" << t->arr[a].age
            << " " << "电话:" << t->arr[a].phonenumber << " " << "地址:" << t->arr[a].address << endl;
    }
}

void modify_people(bbb *t)
{
    string name;
    cout << "请输入想修改的联系人姓名:" << endl;
    cin >> name;
    int a = is_exist(t, name);
    if (a == -1)
    {
        cout << "查无此人!" << endl;
    }
    else
    {
        cout << "请重新输入姓名:" << endl;
        cin >> t->arr[a].name;
        cout << "请输入性别" << endl;
        cin >> t->arr[a].sex;
        cout << "请输入年龄" << endl;
        cin >> t->arr[a].age;
        cout << "请输入电话:" << endl;
        cin >> t->arr[a].phonenumber;
        cout << "请输入地址" << endl;
        cin >> t->arr[a].address;

    }
}

void clean_out(bbb* t)
{
    cout << "您是否确认要清空通讯录  1——是   2——否" << endl;
    int s;
    cin >> s;
    if (s == 1)
    {
        t->size = 0;
        cout << "通讯录已清空!" << endl;
    }

}
int main()
{

    struct bbb  t;
    t.size = 0;
    int select;
    while (1)
    {
        showMenu();
        cin >> select;
        string abc;
        switch (select)
        {
        case 1:
            add_people(&t);
            break;
        case 2:
            show_people(t);
            break;
        case 3:
            delete_people(&t);
            break;
        case 4:
            find_people(&t);
            break;
        case 5:
            modify_people(&t);
            break;
        case 6:
            clean_out(&t);
            break;
        case 0:
            cout << "再见!" << endl;
            system("pause");
            return 0;
        default:
            break;


        }
        system("pause");
        system("cls");
    }

    system("pause");
    return 0;
}

变量(常量)都在哪

const int c_g_a=10;   //const修饰的全局变量——全局常量——全局区
int g_a=10;    //全局变量——全局区


int main()
{
    int l_a=10;   //局部变量——非全局区(栈区)
    static a=10;   //静态变量——全局区
    "hello";   //字符串常量——全局区
    const int c_l_a=10;   //const修饰的局部变量——局部常量——非全局区(栈区)


    system("pause");
    return 0;
}
//栈区数据(局部变量和形参)由编译器管理开辟和释放,该函数执行完自动释放,故不要返回局部变量的地址

堆区

//由程序员管理开辟和释放


int * func()
{
    int * p = new int(10);   
    //该指针是局部变量,存放在栈区,指针中地址存放的数在堆区,new将数据开辟到堆区,返回其地址
    return p;
}
int main()
{
    int *p =func();
    cout<<*p<<endl;
    delete p;   //释放
}

堆区创建数组

int* func()
{
    int *p = new int[5];
    for(int i=0;i<5;i++)
    {
        cin>>p[i];
    }
    return p;
}


int main()
{
    int *arr=func();
    for(int j=0;j<5;j++)
    {
        cout<<arr[j];
    }
    cout<<endl;
    delete[] arr;    //释放堆区的数组,且不是delete[] p

    system("pause");
    return 0;
}

引用

//引用必须初始化,且之后不可改变
int a=10;
int &b=a;      //引用的本质是指针常量 int *const b=&a;    b中存放的始终是a的地址,且可以通过*b去改变a的值

引用做函数参数(形参)

//以引用的方式接收实参,让形参可以修饰实参
void exchange(int &a, int &b)     
{

    int c = a;
    a = b;
    b = c;


}


int main()
{
    int a = 10;
    int b = 20;
    exchange(a, b);             //int &a=a;   别名也叫a
    cout << "a=" << a << endl;
    cout << "b=" << b << endl;       //a=20,b=10

    system("pause");
    return 0;
}

引用做返回值

int& test()
{

    static int a = 10;
    return a;             //返回a的引用,才能用别名去接收,且不要返回局部变量的引用


}


int main()
{
    int &b = test();      //b是a的引用
    test() = 1000;        //函数做左值,则必须返回引用;对原名进行操纵
    cout << "b=" << b << endl;    //别名的值也会改变
                                  //b=1000
    system("pause");
    return 0;
}


//错误案例
int test()
{

    static int a = 10;
    return a;


}

int main()
{

    test() = 1000;       //返回原值,函数不能直接做左值
    //cout << "b=" << b << endl;

    system("pause");
    return 0;
}

常量引用

void test(const int &b)       
{
    //b=40;   错误的,不允许通过别名再修改 const int &b=30,只给只读权限,防止误操作
    cout << "b=" << b<<endl;

}


int main()
{
    int a = 30;
    test(a);


    system("pause");
    return 0;
}

//cont int &b=30  相当于int a=30;     const int &b=a;

函数默认参数

void test(int a,int b,int c);     //函数的声明和实现只能有一个有默认参数

void test(int a, int b = 10, int c = 30)    //默认参数必须放在最后,就是有默认参数的形参右侧的形参必须都有默认参数
{
    cout << a + b + c << endl;
}

int main()
{
    test(10, 20);      //使用用户提供的值,10+20+30
    system("pause");
    return 0;
}

类和结构体

//二者唯一的区别是结构体在默认情况下成员是公共的,类在默认情况下成员是私有的(但是都可以自定义)

#include<iostream>
#include<string>
using namespace std;

struct student                  //学生结构体
{
    string name;
    string number;
    void show()
    {
        cout << "姓名为:" << name << endl;
        cout << "学号为:" << number << endl;
    }
};

int main()
{
    student s1;
    s1.name = "张三";
    s1.number = "123456";
    s1.show();

    system("pause");
    return 0;
}





#include<iostream>
#include<string>
using namespace std;

class student                //学生类
{
public:
    string name;
    string number;             //两个属性:姓名和学号
    void show()                   //行为:打印出姓名和学号
    {
        cout << "姓名为:" << name << endl;
        cout << "学号为:" << number << endl;
    }
};

int main()
{
    student s1;           //通过类创建出一个具体的学生
    s1.name = "张三";
    s1.number = "123456";
    s1.show();

    system("pause");
    return 0;
}
//构造一个类,相当于一个新的数据类型,它下面又包含一系列基本数据类型(int/string能存在的地方,它基本都能在)

类成员的访问权限

1、public

类内可访问、类外可访问

2、protected

类内可访问、类外不可访问,继承该类的子类可以访问

3、private

类内可访问、类外不可访问,继承该类的子类不可访问

中途退出函数

//函数遇到return关键字会直接退出,不再执行剩下的语句
void test(int age)
{
    if(age<0 || age>150)
    {
        cout<<"输入有误!"<<endl;
        return;         //直接退出函数
    }
    else
    {
        //、、、;
    }
    //、、、;
}

成员函数和全局函数

#include<iostream>
#include<string>
using namespace std;

class cube //学生结构体
{
public:
    //设置长
    void set_l(double l)       //成员函数(行为)
    {
        m_l = l;
    }
    //获取长
    double get_l()
    {
        return m_l;
    }
    //设置宽
    void set_w(double w)
    {
        m_w = w;
    }
    //获取宽
    double get_w()
    {
        return m_w;
    }
    //设置高
    void set_h(double h)
    {
        m_h= h;
    }
    //获取高
    double get_h()
    {
        return m_h;
    }
    //获得表面积
    double get_square()
    {
        double square = (m_l * m_h + m_l * m_w + m_h * m_w) * 2;
        return square;
    }
    //获得体积
    double get_volume()
    {
        double volume = m_l * m_h * m_w;
        return volume;
    }
    //利用成员函数比较两个立方体是否完全相同
    bool panduan(cube &c)
    {
        if (m_l == c.get_l() && m_h == c.get_h() && m_w == c.get_w())
        {
            return true;
        }
        else
        {
            return false;
        }
    }
private:
    double m_l;         //成员变量(属性)
    double m_w;
    double m_h;

};
//全局函数判断是否相等
bool issame(cube &c1,cube &c2)
{

    if (c1.get_l() == c2.get_l() && c1.get_h()== c2.get_h() && c1.get_w() == c2.get_w())
    {
        return true;
    }
    else
    {
        return false;
    }
}
int main()
{
    cube c1;         //定义对象
    c1.set_l(2.0);
    c1.set_w(3.0);
    c1.set_h(4.0);
    double s = c1.get_square();//表面积
    cout << "表面积为:" << s << endl;
    double v = c1.get_volume();
    cout << "体积为:" << v << endl;

    cube c2;
    c2.set_l(2.0);
    c2.set_w(3.0);
    c2.set_h(3.0);

    bool b = issame(c1, c2);
    if (b)
    {
        cout << "两个立方体完全相同" << endl;
    }
    else 
    {
        cout << "两个立方体不相同" << endl;
    }
    bool d = c1.panduan(c2);      //关键点,c1结构体去调用函数,传入参数为c2,比较c1和c2的长、宽、高
    cout << d;
    system("pause");
    return 0;
}

类的嵌套

//判断点和圆的位置关系
#include<iostream>
#include<string>
using namespace std;

class Point
{
public:
    //设置点x坐标
    void set_p_x(int x)
    {
        p_x = x;
    }
    //设置点y坐标
    void set_p_y(int y)
    {
        p_y = y;
    }
    //获取点x坐标
    int get_p_x()
    {
        return p_x;
    }
    //获取点y坐标
    int get_p_y()
    {
        return p_y;
    }
private:
    int p_x;   //点x坐标
    int p_y;   //点y坐标
};
class Circle       //圆类
{
public:
    //设置圆心坐标
    void set_c_p(Point p)
    {
        c_p = p;
    }
    //获取圆心
    Point get_c_p()
    {

        return c_p;
    }
    //设置半径
    void set_r(int r)
    {
        c_r = r;
    }
    //获取半径
    int get_r()
    {
        return c_r;
    }
private:
    Point c_p; //圆心坐标
    int c_r;    //半径

};
//全局函数确定点和圆的位置关系
void panduan(Circle& c, Point& p)
{
    int c_x = c.get_c_p().get_p_x();  // 圆心x
    int c_y = c.get_c_p().get_p_y();//圆心y
    int r = c.get_r(); //半径
    int p_x = p.get_p_x();
    int p_y = p.get_p_y();
    int d2 = (c_x - p_x) * (c_x - p_x) + (c_y - p_y) * (c_y - p_y);
    if (d2 == (r*r))
    {
        cout << "点在圆上" << endl;
    }
    else if (d2 < (c.get_r() * c.get_r()))
    {
        cout << "点在圆内" << endl;
    }
    else
    {
        cout << "点在圆外" << endl;
    }
}
int main()
{

    Point p;   //点
    p.set_p_x(3);
    p.set_p_y(0);

    Circle c;    //圆
    c.set_r(3);
    Point c_p;
    c_p.set_p_x(0);
    c_p.set_p_y(0);
    c.set_c_p(c_p);
    panduan(c, p);
    system("pause");
    return 0;
}

分文件编写

//circle.h

#pragma once
#include<iostream>
#include<string>
#include"point.h"
using namespace std;

class Circle       //圆类
{
public:
    //设置圆心坐标        //只保留函数声明和成员声明
    void set_c_p(Point p);
    //获取圆心
    Point get_c_p();
    //设置半径
    void set_r(int r);
    //获取半径
    int get_r();

private:
    Point c_p; //圆心坐标
    int c_r;    //半径

};



//circle.cpp

#include "circle.h"
#include<iostream>
#include<string>
using namespace std;


//设置圆心坐标
void Circle::set_c_p(Point p)     //函数作用域 Circle类下
{
    c_p = p;
}
//获取圆心
Point Circle::get_c_p()
{

    return c_p;
}
//设置半径
void Circle::set_r(int r)
{
    c_r = r;
}
//获取半径
int Circle::get_r()
{
    return c_r;
}



//point.h

#pragma once
#include<iostream>
#include<string>
using namespace std;

class Point
{
public:
    //设置点x坐标
    void set_p_x(int x);
    //设置点y坐标
    void set_p_y(int y);
    //获取点x坐标
    int get_p_x();
    //获取点y坐标
    int get_p_y();

private:
    int p_x;   //点x坐标
    int p_y;   //点y坐标
};



//point.cpp

#include "point.h"
#include<iostream>
#include<string>
using namespace std;


//设置点x坐标
void Point::set_p_x(int x)
{
    p_x = x;
}
//设置点y坐标
void Point::set_p_y(int y)
{
    p_y = y;
}
//获取点x坐标
int Point::get_p_x()
{
    return p_x;
}
//获取点y坐标
int Point::get_p_y()
{
    return p_y;
}



//主程序

#include<iostream>
#include<string>
#include"circle.h"
#include"point.h"
using namespace std;

//全局函数确定点和圆的位置关系
void panduan(Circle& c, Point& p)
{
    int c_x = c.get_c_p().get_p_x();  // 圆心x
    int c_y = c.get_c_p().get_p_y();//圆心y
    int r = c.get_r(); //半径
    int p_x = p.get_p_x();
    int p_y = p.get_p_y();
    int d2 = (c_x - p_x) * (c_x - p_x) + (c_y - p_y) * (c_y - p_y);
    if (d2 == (r*r))
    {
        cout << "点在圆上" << endl;
    }
    else if (d2 < (c.get_r() * c.get_r()))
    {
        cout << "点在圆内" << endl;
    }
    else
    {
        cout << "点在圆外" << endl;
    }
}
int main()
{

    Point p;   //点
    p.set_p_x(3);
    p.set_p_y(0);

    Circle c;    //圆
    c.set_r(3);
    Point c_p;
    c_p.set_p_x(0);
    c_p.set_p_y(0);
    c.set_c_p(c_p);
    panduan(c, p);
    system("pause");
    return 0;
}

构造函数什么时候被调用

//构造函数调用测试
#include<iostream>
#include<string>
using namespace std;

class Point       //创建一个类,会自动生成 默认构造、默认析构、拷贝构造(值拷贝)三个函数
{
public:     
    Point()
    {
        cout << "默认构造调用" << endl;
    }
    Point(int a,int b)       //写了有参构造函数,则编译器不再提供默认构造函数,会提供拷贝构造函数
    {                         //写了拷贝构造函数,则编译器不再提供其他构造函数
        p_x = a;
        p_y = b;
        cout << "有参构造调用" << endl;
    }
    Point(const Point& a)
    {
        p_x = a.p_x;
        p_y = a.p_y;
        cout << "拷贝构造调用" << endl;
    }
    ~Point()
    {                       //析构函数,将堆区(程序员自己开辟)数据释放
        cout << "默认析构调用" << endl;
    }

    int p_x;   //点x坐标
    int p_y;
};

void test()
{
    Point p;      //会调用默认构造
    Point b(0,2);  //调用有参构造
    cout << "b的横坐标为" << b.p_x << endl;
    cout << "b的纵坐标为" << b.p_y << endl;
    Point a(b);   //调用拷贝构造
    cout << "a的横坐标为" << a.p_x << endl;
    cout << "a的纵坐标为" << a.p_y << endl;

}


int main()
{
    test();   //执行完后会调用默认析构



    system("pause");
    return 0;
}


/*运行结果为:
默认构造调用
有参构造调用
b的横坐标为0
b的纵坐标为2
拷贝构造调用
a的横坐标为0
a的纵坐标为2
默认析构调用
默认析构调用
默认析构调用
请按任意键继续. . .
*/

析构函数执行堆区数据的释放

//构造函数调用测试
#include<iostream>
#include<string>
using namespace std;

class Point      
{
public:     
    Point()
    {
        cout << "默认构造调用" << endl;
    }
    Point(int a)
    {
        p_x = a;
        p_y = new int(2);     //创建在堆区,由指针去接收
        cout << "有参构造调用" << endl;
    }

    ~Point()
    {
        if (p_y != NULL)    //指针不指向空,则释放堆区数据
        {
            delete p_y;
            p_y = NULL;
        }
        cout << "默认析构调用" << endl;
    }

    int p_x;   //点x坐标
    int *p_y;
};

void test()
{
    Point p;      //会调用默认构造
    Point b(0);  //调用有参构造
    cout << "b的横坐标为" << b.p_x << endl;
    cout << "b的纵坐标为" << *b.p_y << endl;

}


int main()
{
    test();   //执行完后会调用默认析构

    system("pause");
    return 0;
}

浅拷贝的问题

//浅拷贝带来的问题
#include<iostream>
#include<string>
using namespace std;

class Point      
{
public:     
    Point()
    {
        cout << "默认构造调用" << endl;
    }
    Point(int a)
    {
        p_x = a;
        p_y = new int(2);     //创建在堆区
        cout << "有参构造调用" << endl;
    }
    Point(const Point& a)
    {
        p_x = a.p_x;
        p_y = a.p_y;       //指向同一块堆区内存
        cout << "拷贝构造调用" << endl;
    }
    ~Point()
    {
        if (p_y != NULL)
        {
            delete p_y;
            p_y = NULL;
        }
        cout << "默认析构调用" << endl;
    }

    int p_x;   //点x坐标
    int *p_y;
};

void test()
{
    Point p;      //会调用默认构造
    Point b(0);  //调用有参构造
    cout << "b的横坐标为" << b.p_x << endl;
    cout << "b的纵坐标为" << *b.p_y << endl;
    Point a(b);          //浅拷贝
    cout << "a的横坐标为" << a.p_x << endl;
    cout << "a的纵坐标为" << *a.p_y << endl;     
    //Point a 后定义,但是先被释放,执行析构函数,堆区数据被释放;同样b也会执行相同操作,同一块内存被释放两次,引起错误
}


int main()
{
    test();   //执行完后会调用默认析构



    system("pause");
    return 0;
}

深拷贝解决堆区重复释放的问题

//深拷贝测试
#include<iostream>
#include<string>
using namespace std;

class Point      
{
public:     
    Point()
    {
        cout << "默认构造调用" << endl;
    }
    Point(int a)         //有参构造
    {
        p_x = a;
        p_y = new int(2);     //创建在堆区
        cout << "有参构造调用" << endl;
    }
    Point(const Point& a)
    {
        p_x = a.p_x;
        //编译器默认的浅拷贝 p_y = a.p_y;
        p_y = new int(*a.p_y);     //指针解引用,重新开辟堆区内存——深拷贝
        cout << "拷贝构造调用" << endl;
    }
    ~Point()
    {
        if (p_y != NULL)
        {
            delete p_y;
            p_y = NULL;
        }
        cout << "默认析构调用" << endl;
    }

    int p_x;   //点x坐标
    int *p_y;
};

void test()
{
    Point p;      //会调用默认构造
    Point b(0);  //调用有参构造
    cout << "b的横坐标为" << b.p_x << endl;
    cout << "b的纵坐标为" << *b.p_y << endl;
    Point a(b);
    cout << "a的横坐标为" << a.p_x << endl;
    cout << "a的纵坐标为" << *a.p_y << endl;    //执行各自的析构函数,不再报错
}


int main()
{
    test();   //执行完后会调用默认析构



    system("pause");
    return 0;
}

初始化列表

//通过初始化列表给类属性赋值
#include<iostream>
#include<string>
using namespace std;

class Phone
{

public:
    Phone(string name)     //有参构造
    {
        p_name = name;
    }

    string p_name;
};

class Student
{
public:
    Student(string name,int age,Phone phone):s_name(name),s_age(age),s_phone(phone)     //初始化列表
    {

    }

    string s_name;
    int s_age;
    Phone s_phone;     //类的嵌套(一个类作为另一个类的成员变量)
};
void test()
{
    Phone p("SAMSUNG");    
    Student s("张三", 18, p);
    cout << "姓名:" << s.s_name << " 年龄:" << s.s_age << " 手机品牌:" << s.s_phone.p_name << endl;
}


int main()
{

    test();

    system("pause");
    return 0;
}
//构造时,先构造Phone(内层),再构造Student(外层),析构的顺序与之相反

静态成员变量

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

2、编译阶段就分配内存

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

静态成员函数

1、通过对象来访问

2、通过类名来访问

3、只能访问静态成员变量

#include<iostream>
#include<string>
using namespace std;

class Point
{
public:
    static void function()
    {
        cout << "lalall" << endl;
        a = 100;    //静态成员函数只能访问静态成员变量   非静态成员函数、静态成员函数和静态成员变量,不属于类的对象上,大家共享一份(只有非静态成员变量属于类的对象上)
    }
    static int a;
};
int Point::a = 0;         //静态成员变量,类内声明,类外初始化

void test()
{
    Point p;
    p.function();     //通过对象访问
    Point::function();  //通过类名访问,只有静态成员函数可以,是所有对象共享一份成员函数的体现
}


int main()
{
    test();   //执行完后会调用默认析构



    system("pause");
    return 0;
}

只有非静态成员变量属于类的对象上

#include<iostream>
#include<string>
using namespace std;

class Point
{
    int a;
    int b;
};

void test()
{
    Point p;
    cout << sizeof(p) << endl;        //8
}


int main()
{
    test();   //执行完后会调用默认析构



    system("pause");
    return 0;
}

成员变量和形参名称冲突 this指针

#include<iostream>
#include<string>
using namespace std;

class Point
{
public:
    Point(int a)
    {
        a = a;  //和成员变量a无关  ,修改方式:1、改名称  2、this->a=a;    this指针指向成员函数被调用的对象(该处为p)
        //cout << a << endl;
    }

    int a;
};

void test()
{
    Point p(2);
    cout << p.a << endl;    //乱码
}


int main()
{
    test();   //执行完后会调用默认析构



    system("pause");
    return 0;
}

*this返回该对象

#include<iostream>
#include<string>
using namespace std;

class Point
{
public:
    Point(int a)
    {
        this->a = a; 
    }
    Point& ptop(Point& p)     //返回类的引用,    如果返回值的话(Point),会新创建类,不再是p2
    {
        this->a += p.a;
        return *this;
    }    

    int a;
};

void test1()
{
    Point p1(10);
    Point p2(10);
    p2.ptop(p1).ptop(p1).ptop(p1);    //链式编程
    cout << p2.a << endl;
}
int main()
{
    test1();
    system("pause");
    return 0;
}

this 指针本质是指针常量

P *const this 即this是指向P的一个指针常量

//指针常量 int * const p = &a;  p=&b表达式是错误的,*p = 20是允许的 故:
//P *const this  即this是指向P的一个指针常量
class P
{
public:
    P(int a)
    {
        this->m_a=a;    //指针常量所指向的内存地址的值是可以修改的
        //this =NULL;  //所指向的内存地址是不允许修改的
    }

    int m_a;
};

成员函数后加const 常函数

class Point
{
public:
    void print_a(int a) const      //常函数,const修饰this指针,this指向内存的值不允许修改
    {
        //this->m_a = a; 
        this ->m_b = 100;     //允许,mutable定义特殊变量,允许修改
        cout << m_a << endl;
    }

    int m_a;
    mutable int m_b;
};

void test()
{
    const Point p;    //常对象    常对象只能调用常函数,不能调用普通的成员函数
    //p.m_a = 100;   不允许修改
    p.m_b=100;   //允许
}

int main()
{
    test();

    system("pause");
    return 0;
}

构造和析构函数上不允许使用类型限定符(如const)

友元(可以访问类中的私有成员)

全局函数做友元
#include<iostream>
#include<string>
using namespace std;

class Building
{
    friend void test(Building* building);   //全局函数做友元,可以访问私有成员
public:
    Building()
    {
        m_s = "啦啦啦啦";
        m_b = "不不不不不不";
    }

    string m_s;
private:
    string m_b;
};
void test(Building* building)
{
    string a = building->m_s;
    cout << a << endl;
    string b = building->m_b;
    cout << b << endl;
}

int  main()
{
    Building building;    //默认构造
    test(&building);

    system("pause");
    return 0;
}
类做友元
#include<iostream>
#include<string>
using namespace std;

class Building
{
    friend class goodguy;   //goodguy类做友元
public:
    Building();
    string m_s;
private:
    string m_b;
};

class goodguy
{
public:
    void visit();
    Building building;   //类的嵌套
};

Building::Building()     //类外写成员函数(构造函数)
{
    m_s = "lallalal";
    m_b = "bbbbbbb";
}

void goodguy::visit()
{
    cout << building.m_s << endl;
    cout << building.m_b << endl;
}
int  main()
{
    goodguy guy;
    guy.visit();
    system("pause");
    return 0;
}



//不用类的嵌套
#include<iostream>
#include<string>
using namespace std;


class Building
{
    friend class goodguy; //类做友元
public:
    Building();  //构造函数声明,类外实现
    string m_s;
private:
    string m_b;
};

class goodguy
{
public:
    goodguy();
    void visit();

    Building* building; //指针
};

Building::Building()
{
    m_s = "lallalal";
    m_b = "bbbbbbb";
}
goodguy::goodguy()      //构造函数实现
{

    building  = new Building;     //堆区开辟一个Building,赋给指针building
}
void goodguy::visit()
{
    cout << building->m_s << endl;
    cout << building->m_b << endl;
}
int  main()
{

    goodguy guy;
    guy.visit();
    system("pause");
    return 0;
}
成员函数做友元
//(类中的某个成员函数做友元)
#include<iostream>
#include<string>
using namespace std;

class Building;
class goodguy        //要把该类写在Building类前面,否则第x行还是会报错
{
public:
    goodguy();
    void visit();
    void visit2();
    Building* building;
};
class Building
{
    friend void goodguy::visit();
public:
    Building();
    string m_s;
private:
    string m_b;
};

Building::Building()
{
    m_s = "lallalal";
    m_b = "bbbbbbb";
}
goodguy::goodguy()
{

    building  = new Building;
}
void goodguy::visit()
{
    cout << building->m_s << endl;
    cout << building->m_b << endl;    //第x行
}
void goodguy::visit2()
{
    cout << building->m_s << endl;
}
int  main()
{
    goodguy guy;
    guy.visit();
    guy.visit2();
    system("pause");
    return 0;
}

运算符重载(加法)

#include<iostream>
#include<string>
using namespace std;

class Person
{
public:
    Person operator+(Person& a);         //重载运算符-也是类似
    int m_a;
    int m_b;

};

Person Person::operator+(Person& a)      //成员函数重载+号
{
    Person c;
    c.m_a = this->m_a + a.m_a;
    c.m_b = this->m_b + a.m_b;
    return c;
}
//Person operator+(Person& a, Person& b)   //全局函数重载+号
//{
//    Person c;
//    c.m_a = a.m_a + b.m_a;
//    c.m_b = a.m_b + b.m_b;
//    return c;
//}

Person operator+(Person &a,int b)      //函数重载,函数名相同,但是参数不同
{
    Person c;
    c.m_a = a.m_a + b;
    c.m_b = a.m_b + b;
    return c;
}
void test()
{
    Person a;
    a.m_a = 10;
    a.m_b = 20;

    Person b;
    b.m_a = 10;
    b.m_b = 20;
    Person c = a + b;     //本质上是     Person c = a.operator+(b);      Person c = operator+(a,b)
    cout << c.m_a << endl;
    cout << c.m_b << endl;

    Person d = a+10;      //Person + int
    cout<<d.m_a<<endl;     //20
    cout<<d.m_b<<endl;     //30
}
int  main()
{
    test();
    system("pause");
    return 0;
}

运算符重载(左移运算符)

//(直接输出类的成员变量的值)
#include<iostream>
#include<string>
using namespace std;

class Person
{
public:
    Person(int a, int b)     //有参构造函数可以解决私有成员访问问题
    {
        m_a = a;
        m_b = b;
    }
    friend ostream& operator<<(ostream& cout, Person a);

private:
    int m_a;
    int m_b;

};

ostream& operator<<(ostream &cout, Person a)    //cout 数据类型为标准输出流ostream,且cout唯一所以要用引用
{
    cout << a.m_a << " " << a.m_b;
    return cout;
}
void test()
{
    Person a(10, 20);
    cout << a << endl;    //本质上是operator<<(cout,a)
}
int  main()
{
    test();
    system("pause");
    return 0;
}

编译器默认提供的类的函数

1、默认构造

2、默认析构

3、拷贝构造

4、赋值运算符 operator=,(类可以直接进行赋值运算)

#include<iostream>
#include<string>
using namespace std;

class Person
{
public:
    Person(int age)
    {
        m_age = new int(age);   //将age数据开辟到堆区
    }
    int* m_age;
};

void test()
{
    Person p1(18);
    cout << "p1的年龄为:" << *p1.m_age << endl;
    Person p2(20);
    p2 = p1;    //直接进行赋值运算
    cout << "p2的年龄为:" << *p2.m_age << endl;

}
int  main()
{
    test();
    system("pause");
    return 0;
}

运算符重载(赋值运算)

#include<iostream>
#include<string>
using namespace std;

class Person
{
public:
    Person(int age)
    {
        m_age = new int(age);   //将age数据开辟到堆区
    }

    Person& operator=(Person& a)
    {
        if (m_age != NULL)
        {
            delete m_age;
            m_age = NULL;
        }
        this->m_age = new int(*a.m_age);    //深拷贝,解决堆区重复释放的问题,返回Person的引用是为了连续赋值
        return *this;
    }
    int* m_age;
};


void test()
{
    Person p1(18);
    cout << "p1的年龄为:" << *p1.m_age << endl;
    Person p2(20);
    Person p3(30);
    p3 =p2 = p1;    //直接进行赋值运算
    cout << "p2的年龄为:" << *p2.m_age << endl;
    cout << "p3的年龄为:" << *p3.m_age << endl;

}
int  main()
{
    test();
    system("pause");
    return 0;
}

继承

class 子类 : 继承方式 父类

#include<iostream>
#include<string>
using namespace std;

class basepage
{
public:
    void header()
    {
        cout << "aaaaaa" << endl;
    }
    void footer()
    {
        cout << "bbbbbb" << endl;
    }
    void left()
    {
        cout << "ccccccc" << endl;
    }
    void right()
    {
        cout << "dddddddd" << endl;
    }
};

class java:public basepage
{
public:
    void content()
    {
        cout << "this is java" << endl;
    }
};
void test()
{
    java ja;
    ja.header();
    ja.footer();
    ja.left();
    ja.right();
    ja.content();
}

int  main()
{
    test();
    system("pause");
    return 0;
}

继承方式

父类中的private,子类不可访问

1、公共继承

class 子类 : public 父类

public——public

protected—— protected

2、保护继承

class 子类 : protected 父类

public、protected——protected

3、私有继承

class 子类 : private 父类

public、protected——private

利用开发人员命令提示工具查看对象模型

C:\Users\xx\source\repos\Project1\Project1>cl /d1 reportSingleClassLayoutbasepage 源.cpp
//C:\Users\xx\source\repos\Project1\Project1>为cpp文件所在路径 basepage为类名

子类中同名属性的访问

#include<iostream>
#include<string>
using namespace std;

class base
{
public:
    base()
    {
        m_a = 100;
    }
    int m_a;

};

class son :public base
{
public:
    son()
    {
        m_a = 200;
    }
    int m_a ;
};

void test()
{
    son s;
    cout << s.m_a << endl;     //直接访问为子类的属性
    cout << s.base::m_a << endl;   //父类中同名属性访问需要加上作用域

}
int  main()
{
    test();
    system("pause");
    return 0;
}



#include<iostream>
#include<string>
using namespace std;

class base
{
public:
    base()
    {
        m_a = 100;
    }
    void aaaa()
    {
        m_a = 200;
    }
    void aaaa(int b)
    {
        m_a = 500;
    }
    int m_a;

};

class son :public base
{
public:
    son()
    {
        m_a = 300;
    }
    void aaaa()
    {
        m_a = 400;
    }

    int m_a ;
};

void test()
{
    son s;
    s.aaaa();
    cout << s.m_a << endl;    //400
    s.base::aaaa();
    cout << s.base::m_a << endl;    //200
    s.base::aaaa(10);          //只要出现同名,父类中的函数都会被隐藏必须加作用域才能访问
    cout << s.base::m_a << endl;    //500
}
int  main()
{
    test();
    system("pause");
    return 0;
}

多继承

class 子类 :public 父类1,public 父类2……

#include<iostream>
#include<string>
using namespace std;

class base1
{
public:
    base1()
    {
        m_a = 100;
    }
    int m_a;

};

class base2
{
public:
    base2()
    {
        m_b = 200;
    }
    int m_b;
};
class son :public base1,public base2     //多继承
{
public:
    son()
    {
        m_c = 300;
    }

     int m_c ;
};

void test()
{
    son s;
    cout << s.m_a << endl;
    cout << s.m_b << endl;
    cout << s.m_c << endl;
}
int  main()
{
    test();
    system("pause");
    return 0;
}

父类的引用指向子类的对象

class Animal
{
public:

    void speak()
    {
        cout << "动物在说话" << endl;
    }
};

class cat:public Animal
{
public:

    void speak()
    {
        cout << "猫在说话" << endl;
    }
};
void dospeak(Animal &animal)      
{
    animal.speak();      //编译的时候提前分配空间,输出一定是“动物在说话”
}

void test()
{
    cat a;
    dospeak(a);      //允许父类的引用指向子类的对象 Animal &animal = cat,不需要做类型转换
}

动态多态(父类函数前加virtual)

满足条件
1、有类的继承关系
2、子类重写父类的虚函数(函数返回类型、函数名、参数条件都相同)
3、全局函数中父类通过指针或引用指向子类对象

class Calculator
{
public:
    virtual int get_result()=0;   
    //纯虚函数
    //有纯虚函数的类称为抽象类
    //1、不能实例化对象;2、子类需重写纯虚函数,否则仍为抽象类
    int a;
    int b;
};       //抽象的计算器类

class ADDCalculator : public Calculator
{
public:
    int get_result()
    {
        int c = this->a + this->b;
        return c;
    }
};
class MULCalculator : public Calculator
{
public:
    int get_result()
    {
        int c = this->a * this->b;
        return c;
    }
};
class SUBCalculator : public Calculator
{
public:
    int get_result()
    {
        int c = this->a - this->b;
        return c;
    }
};
void test()
{
    //多态的两种实现方式
    //1、父类的指针指向子类的对象
    Calculator* abc = new SUBCalculator;   
    abc->a = 10;
    abc->b = 20;
    int c = abc->get_result();
    cout << c << endl;
    delete abc;

    //2、父类的引用指向子类的对象
    SUBCalculator A;
    Calculator& cal = A;
    cal.a = 10;
    cal.b = 10;
    int d = cal.get_result();
    cout << d << endl;

}

文章标题:c++学习

本文作者:Echo

发布时间:2020-11-17, 22:55:06

最后更新:2020-11-27, 22:34:26

原始链接:http://dmzecho.github.io/2020/11/17/c++%E5%AD%A6%E4%B9%A0/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录