C++学习摘要[黑马教学视频]
- 函数-值传递
- 函数调用时,实参传递给形参。
- 值传递时,形参改变,不会改变实参
- 函数-4种形式
- 无参无返
- 有参无返
- 无参有返
- 有参有返
- 函数-声明
- 作用:告诉编译器函数名称以及如何调用函数。函数的主体可以单独定义。
- 函数可以多次被声明,但是函数的定义只有一次
- 指针-指针变量定义和使用
- 作用:直接访问内存。
- 内存编号时从0开始的,一般用十六进制表示
- 可以利用指针变量保存地址
- 语法: 数据类型 * 变量名
指针变量前面加 * 号表示【解引用】,找到指针指向的内存中的数据int a=10; int * P; P = &a;
- 指针-内存空间
- 32位系统,占用4个字节,64位占用8字节。
- 和char * ,double *,float *等无关。
- 空指针:
- 指向内存编号为0的地址空间,用于初始化指针变量。
- 内存不可以访问
- 野指针:
- 指针变量指向非法的内存空间,例如: int *p=(int *)0x1100;
- 访问野指针会造成异常
- Const 修饰指针
- Const 修饰指针--常量指针 const int *p =&a;指针的指向可以修改,指向的值不可以修改
- Const 修饰常量--指针常量(this指针) int * const p =&a;指针的指向不可以修改,指向的值可以修改
- 既修饰指针又修饰常量 const int * const p= &a;都不可以修改
- 指针和函数
- 值传递和地址传递 如使用&a传递,使用*a接收。地址传递可以修饰实参,依据需求选择传递方式。
- 结构体
- 创建结构体变量时,struct关键字可以省略;使用.访问成员变量
- 如何使用指针访问结构体变量: *p的类型要和结构体名一致,访问变量使用->
- 结构体嵌套结构体
- 结构体作为函数的参数,值传递和地址传递
- 结构体const使用。值传递可能引起内存增加,加入const 可以防止函数体内对变量的误操作。
- 内存分区模型
- 代码区:存放函数体的二进制代码,由操作系统进行管理的,是共享的只读的
- 全局区:存放全局变量和静态变量以及常量,该区域的数据在程序结束后由操作系统释放
- 栈区: 由编译器自动分配和释放,存放函数的形参、局部变量等;不要返回局部变量的地址,栈区开辟的数据由编译器管理。
- 堆区: 由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。使用new关键字开辟空间,释放delete
- NEW操作符
- 语法:new 数据类型 利用new创建的数据,会返回数据对应的数据类型 int *p=new int(10); int * arr =new int[10]
- 引用
- 作用:给变量起别名。语法:数据类型 & 别名=原名。
- 注意事项:必须初始化;初始化后不可更改;
- 引用传递:形参会修饰实参,可以简化指针方法形参修饰实参。起别名。
- 引用做返回值:不要返回局部变量的引用;如果函数的返回值是引用,函数可以做左值
- 引用本质:指针常量 int * const p =&a 指针的指向不可以修改,指向的值可以修改。
- 常量引用:修饰形参防止误操作
- 函数
- 默认参数:语法
- 某个位置有默认参数,右侧都要有
- 如果函数声明有默认参数,那么函数定义就不能有默认参数了(声明和实现只能有一个默认参数)
- 占位参数 语法:返回值类型 函数名 (数据类型){} 形参列表中可以有占位参数,调用时必须填补该位置。
- 函数重载 函数名可以相同
- 同一个作用域下
- 函数名相同
- 函数参数类型不同,或者个数不同,或者顺序不同
- 注意事项
- 引用作为重载条件
- 重载遇到默认参数出现的二义性,尽量避免这种情况
- 默认参数:语法
- 类和对象--对象特性 --20231125
- 和strcut区别,类默认成员变量属性是私有的,结构体是共有的。可以控制成员属性的私有化。 构造函数 语法 类名(){} 主要用于创建对象时对对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用。
- 构造函数没有返回值也不写void
- 函数名称与类名相同
- 构造函数可以有参数,因此可以发生重载
- 程序在调用对象时候会自动调用构造,无须手动调用而且只会调用一次
- 析构函数 语法 ~类名(){} 主要作用在于对象销毁前系统自动调用,执行一些清理工作。
- 析构函数没有返回值也不写void
- 函数名称于类名相通,在名称前加上~
- 析构函数不可以有参数,因此不可以发生重载
- 程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次。
- 构造函数分类和调用
- 两种分类方式:按参数:有参构造和无参(默认)构造。按类型,普通构造和拷贝构造(格式 const 类名 &变量)。
- 调用:
- 括号法 调用默认(无参)构造函数的时候,不要(),编译器会认为是声明,不会认为是在创建对象;例子:person p2(10);person p3(p2)
- 显示法 person p2 = person(10);person p3 = person (p2); person(10)匿名对象 特点:当前行执行结束后,系统会立即回收掉匿名对象。不要利用拷贝构造函数初始化匿名对象。编译器会认为 Person (p3)=== Person p3;对象重定义
- 隐士转换法 person p4 = 10;相当于person p4 = person(10);person p5 = person p4;
- 拷贝构造函数调用时机
- 使用一个已经创建完毕的对象来初始化一个新对象
- 值传递的方式给函数参数传递
- 值方式返回局部对象
- 构造函数的调用规则 默认情况下,C++编译器至少会给一个类添加3个函数
- 默认构造函数
- 默认析构函数
- 默认拷贝构造函数,对属性进行值拷贝
- 调用规则如下:
- 如果用户定义有参构造函数,c++不再体哦那个默认无参构造(空实现)函数,但会提供默认拷贝构造
- 如果用户定义拷贝构造函数,c++不再提供其他构造函数
- 深拷贝和浅拷贝
- 浅拷贝:简单的赋值拷贝操作;问题:堆区的内存重复释放
- 深拷贝:在堆区重新申请空间,进行拷贝操作;
- 初始化列表 语法:构造函数():属性1(值1),属性2(值2)...{}
- 类对象作为类成员 对象成员 B类中有对象A作为成员
- 当创建B时,先构造类对象,再构造自身
- 析构时,与构造顺序相反
- 静态成员 在成员变量或者成员函数的前面加上关键字static,称为静态成员
- 静态成员变量
- 所有对象共享同一份数据
- 在编译阶段分配内存
- 类内声明,类外初始化
- 静态成员变量两种访问方式:通过对象访问;通过类名直接进行访问
- 静态成员变量也是有访问权限的
- 静态成员函数
- 所有对象共享同一个函数
- 静态成员函数只能访问静态成员变量
- 两种访问方式:对象,类名访问
- 静态成员函数只能访问静态成员变量
- 静态成员函数也是有访问权限的
- 静态成员变量
- 类和对象--对象模型和this指针
- 成员变量和成员函数分开存储 C++中类的成员变量和成员函数分开存储,只有非静态成员变量才属于类的对象上。
- This指针
- 每一个非静态成员只有一份函数实例,也就是说多个同类型的对象会共用同一块代码。那么这一块代码如何区分是哪个对象调用自己的呢?This 指针指向被调用的成员函数所属的对象
- this指针是隐含在每一个非静态成员函数内的一种指针
- this指针不需要定义,直接使用
- 用途:a:当形参和成员变量同名时,可用this指针来区分(解决名称冲突) b:在类的非静态成员函数中返回对象本身,可使用return *this
- 空指针访问成员函数
- const 修饰成员函数【20231126】
- 常函数
- 成员函数后加const称为常函数
- 常函数内不可以修改成员属性
- 成员属性声明时加关键字mutable后,在常函数中依然可以修改
- 常对象
- 声明对象前加const称该对象为常对象
- 常对象只能调用常函数
- 常函数
- 类和对象--友元
- 关键字 friend
- 全局函数做友元
- 类做友元
- 成员函数做友元
- 关键字 friend
- 运算符重载【待定】
类和对象--继承 减少重复代码,子类也成为派生类父类成基类 - 语法:class 子类:继承方式 父类
- 继承方式
- 公共继承
- 保护继承
- 私有继承
-
继承中的对象模型
- 父类中所有非静态成员属性都会被子类继承,但是私有的成员属性会被编译器隐藏而访问不到
- 继承中构造和析构顺序
- 继承中先构造父类,再构造子类。析构的顺序相反。
- 继承同名成员处理方式
- 访问子类同名成员(属性或函数),直接访问
- 访问父类同名成员(属性或函数),需要加作用域
- 如果子类出现和父类同名的成员函数,子类的同名成员会隐藏掉父类所有同名成员函数。如果想访问,需要加作用域。
- 继承同名静态成员处理方式 静态成员和非静态成员出现同名,处理方式一致
- 访问子类同名成员,直接访问即可
- 访问父类同名成员,需要加作用域
- 可以通过对象访问(例如:s.Base::m_A),也可以通过类名访问(例如:Son::Base::m_A)
- 多继承语法 语法: class 子类:继承方式 父类1,继承方式 父类2... 多继承会引发父类中有同名成员出现,需要加作用域区分。实际开发中不建议使用。
- 菱形继承 虚继承
-
羊驼有两份数据,需要使用作用域区分。
- 继承之前加上关键字virtual变为虚继承;
-
- 多态
- 基本概念
- 静态多态:函数重载和运算符重载属于静态多态,复用函数名
- 动态多态:派生类和虚函数实现运行时多态
- 区别
- 静态多太的函数地址早绑定----编译阶段确定函数地址
- 动态多态的函数地址晚绑定----运行阶段确定函数地址
- 动态多态实现条件
- 有继承关系
- 子类重写父类的虚函数
- 动态多态使用
- 父类的指针或引用,指向子类对象 例如:void doSpeak(Animal &animal)// Animal & animal = cat
- 原理解析:
- 纯虚函数和抽象类
- 语法:virtual 返回值类型 函数名 (参数列表)=0;
- 特点:
- 当类中有纯虚函数时候,称为抽象类,无法实例化对象
- 子类必须重写抽象类中的纯虚函数,否则也属于抽象类
- 虚析构和纯虚析构 多态使用时,如果子类有属性开辟在堆区,那么父类指针在释放时无法调用到子类的析构代码。
- 解决方式:将父类中的析构函数改为虚析构或者纯虚析构
- 纯虚析构和虚析构相同点:
- 可以解决父类指针释放子类对象
- 都需要具体的函数实现
- 纯虚析构和虚析构区别:
- 如果时纯虚析构,该类属于抽象类,无法实例化对象
- 语法
- virtual ~类名(){}
- virtual ~类名(){} = 0
- 基本概念
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?