在C中要想输入和输出 我们会经常用到
在C++中头文件的命名风格不用.h
c++中 为什么要写<iostream>和using namespace std;-CSDN博客
这俩个函数是在std命名空间下定义的
ceil()函数向上取整
round( )四舍五入取整
c语言没有 是C++中的一种基本数据类型(内置数据类型)
只用一个字节
非零的数组都是true
一块有类型的内存
我们在C语言中在堆区申请内存空间是用malloc 释放用free
如果不释放会造成这段内存但用以后无法被访问 造成内存的泄露
在c++用我们new 开辟堆区空间 delete释放堆区空间
new与malloc相同的是 都可以返回开辟这段空间的首元素的地址
都是不同点是 new返回的地址类型是自动匹配存储信息的内容的,而malloc是返回的空类型需要强制类型转换
注意在开辟空间的时候初始化 在c中用malloc是不可以的,但是C++的new可以实现这个功能
中间是没有等号的
如果不初始化里面的数据是随机数
delete
在C++语法上来看,引用是给变量起了个别名,不占用空间
类型& 引用变量名 =引用实体
引用是给变量起别名,那前提肯定得有实体变量
引用是给变量起别名,给空起了个别名没意义
引用的实质是一个指针常量,是一个指向方向固定的指针,所有它不能更改指向,也就不能改变引用关系
不可寻址、一般没有变量名的值
const 类型 引用名 =引用实体
参数的传递方式有俩种
值传递(只是一个传值的过程),但是传递的值可能是地址,也可能是基本类型数据
引用传递
优点
指针要判空的,但是引用不用 可以避免很多麻烦
在内存中不会产生返回值的副本
1.引用必须进行初始化,但是指针可以不初始化,为野指针
2.引用不用初始化为空,但是指针可以初始化为空,为空指针
3.引用与变量的关系不能改变,但是指针的指向确可以改变
4.引用所占的空间大小为 类型大小所对应的字节,而指针4/8Byte
6.引用的++是指别名所在的那段空间数据的++,而指针的++是指向的移动
函数调用,是主调函数向被调函数传值,然后被调函数返回结果给主调函数的一个过程
这个过程是需要函数栈来辅助的
栈是向下生长的,就是由高地址向低地址开辟空间
堆是向上生长的,就是由低地址向高地址开辟空间
形参在入栈的时候是从右向左入栈的,而实参传值给形参的时候是从左向右传值(相当于出栈的顺序)
函数的默认参数是在函数调用的过程中发生的,实参在没有传递给形参值之前,形参就已经有了默认参数
剖析下上面程序的执行过程当函数执行到主函数func位置时,会由函数的调用,主调函数调用被调函数,被调函数会调用一个新的函数栈,被调函数的形参从右向左入栈,一次是c、b、a,然后主调函数向被调函数传值,按照从左到右的顺序传值
原因:主函数中你认为值2会传给b但是实际上 他是按从左到右的顺序去传递的 2被赋值给了a b没有被赋值 所以会报错
原因:C语言函数的组成与C++函数组成有区别
C中函数就是由函数名组成的
C++函数是由函数名+参数组成的
也就是说C++中参数不同但函数名相同的函数是不同的函数,而C语言里只要函数名一样就是相同函数了
所以C语言中不存在在函数的重载
函数名可以相同,提高复用性
在调用相同函数名的函数的时候,通过参数列表的不同来却分到底进入哪个函数
参数列表的不同可以是参数个位的不同,参数顺序的不同,参数类型的不同等等
引用分为左值引用 右值引用 和 万能引用
可以用这个来作为函数参数的不同
观看下面的示例,确实符合函数重载的定义(函数名相同,参数列表不同可以重载),但是仔细观察第一个函数是有一个默认参数的,理论上它传递2个值就可以。而第二个函数就是传递俩个参数,这就会造成编译器无法确定你到底要将这俩个值传递给谁
编译器无法仅根据返回值的类型来判断是否能够重载
1.结束条件
2.前进
3.递归的调用
4.回退
为什么斐波那契数列能用递归
能写出递归树
比如你想算第五项的斐波那契数列
你要想求5 就必须得知道4和3 你要想知道4和3 就必须得知道2和1 你要想知道 2和 1 就必须知道1 和 0 而1 和0 我们还真知道 所以符合递归
我们在C语言中都学过struct类型 他是一种复合类型 里面可以定义各种基本类型的变量 但是不知道你是否留意 struct类里面不能定义函数
例子1:
通过上面的这个例子我们可以看出,
struct类型在C中不可以定义函数,但是在C++中可以定义函数
在看一下第二个例子
例子2
通过例子2我们可以看出,在C中如果不用typedef关键字,我们定义结构体变量只能用struct Student,使用Student是不合法的,而在C++中这俩种方式都是合法的
在C中结构体名称不可以定义变量,但是C++中结构体名称可以定义变量
结合这俩点我们不难看出 C++对结构体类型进行了某种程度的升级
“某种程度”–>函数的升级,以及定义“变量”的升级,都更加方便了
这种升级就是把struct升级成了C++语言中的类
这就是我们今天的主题,在这里就引出了
可以把类看成就C中struct类型的plus版
结构体和类的唯一区别就是默认访问权限和继承权限
1.封装
2.继承
3.多态
!!C++中认为万事万物皆为对象,对象有它的属性和行为
属性–>成员变量
行为–>成员函数
格式:class 类名 { 访问权限:属性、行为};
不要忘了分号!!!
和int一个a等于10一样,必须加分号
意义:讲属性和行为放在一起,并加以权限控制
C语言太自由了主函数中向修改结构体类型里面变量的值就修改
C++把它们封装了起来,加了访问权限的控制
访问权限:公有的、受保护的和私有的
1.public
2.protected
3.private
C++中类下默认访问权限是private
struct类的默认访问权限是public,因为要兼容C中的struct类
类的作用域
public–>共有的作用域为 类内函数、子类和对象
protected–>受保护的作用域为 类内函数、子类
private–>私有的作用域 类内函数
this关键字
先看个例子
语句1要执行的是把字符串syc赋值给s1的_name
语句2要执行的是把字符串lh赋值给s2的_name
this指针里面存的就是s1和s2的地址
this关键字是指向当前对象的指针,谁调用这个函数,this指针就指向谁
本质:this指针的本质是在实参传值给形参的过程中,形参多了一个指针常量this用来接收调用这个函数对象的地址
特点:其实this指针的特性在上一个模块(this指针的引出)已经讲解的差不多了,这里简要说明:
1.this指针的类型:指针常量指向调用这个函数的对象
2.只能在“成员函数”的内部使用
3.this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所4.以对象中不存储this指针。
5.this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递此处为摘抄。
类的对齐和结构体的对齐很相似
注意:计算类的大小不包括成员函数,只计算成员变量
构造函数是在创建对象的时候对成员变量进行赋值的一个函数
<注意>
构造函数是对成员变量进行赋值,而不是初始化
因为是先有了对象同时对象里面的成员变量被实例化了,之后对象调用构造函数,对成员变量进行赋值
构造函数的格式
类名+(){ }
观察这个格式我们可以看出它相对于普通函数的相同点和不同点
相同点:它与普通函数一样都有函数名、参数列表、函数体
不同点:它没有返回值 并且它强制要求函数名必须是类名
把类名作为函数名可以很明显的区分出来 这个是构造函数 方便你找到它
无参默认构造函数
解释:如果在类里面没有自己定义构造函数的话,编译器会自动提供一个无参的默认构造函数
<注意>:如果定义了构造函数,那么编译器不会提供默认构造函数
构造函数的分类及调用
分类
按参数分:有参构造、无参构造
按类型分:普通构造、拷贝构造
构造函数的调用
1.括号调用(常用)
2.显示调用
3.隐式调用
如何禁止隐式调用–>使用explicit关键字
但是要注意的和普通函数一样,当出现默认参数的时候,要仔细观察它是否符合函数重载
看下面这段代码:
看着是不是很想是一个无参构造函数,但是实际上编译器很认为他是一个函数的声明;
在调用默认构造函数的时候不用加括号!!!!否则会被编译器认为是函数的声明!!!!!!!
用于释放成员变量指向的堆区空间
当对象要被销毁的前 编译器自动调用析构函数
~类名(){ }
与构造函数比 多了一个~表示析构函数
析构函数不存在重载,它参数列表参数为空
delete先调用析构函数,释放掉成员变量所指向的堆区空间,然后调用free函数把对象所在的堆区空间释放
从返回值上来看
new返回的地址是自动转换的
malloc返回的地址是需要强转的
从名称上
new是运算符,可以调用重载运算符函数(operator)进行重载
而malloc函数是C语言的库函数,C语言没有函数的重载,所以malloc没有函数重载
参数上来看
new是不需要传参的,它分配空间的大小由编译器根据类型计算得出
而malloc是需要传参的,传递的是具体开辟空间的大小的字节数
从底层在来看
new是先调用malloc函数,先在堆区中开辟,如果这段空间的类型是类的话,会调用构造函数,对对象里面的成员变量进行赋值
而malloc仅仅只是在堆区中开辟空间
从空间开辟失败的后果上来看
new开辟空间失败会抛出一段异常
而malloc会返回一个空指针
从已分配内存不够用扩张上来看
new不支持内存的扩张
malloc可以调用realloc扩张内存
1.从参数上来看–>delete不需要传递参数,free需要传参
2.从底层上来看
delete关键字会先调用析构函数,再调用free函数
具体过程如下:delete函数会先调用析构函数释对象中成员变量所指向的堆区空间,然后再调用free函数释放对象所在的堆区空间
而free函数,不会调用析构函数,只释放对象所在的堆区空间
所以当成员变量没在堆区申请空间的时候,也就是析构函数不起作用的时候 delete可以替换free 但是别给自己找麻烦还是别这么用了!
初始化列表与构造函数紧密相关的
构造函数参数列表的后面加上:成员变量1(参数列表的值),成员变量2(参数列表的值)…
当父类没有无参构造时,需要通过父类名调用父类的构造函数
非类成员,通过成员名(值)初始化
类成员,通过对象调用构造函数
因为对象的初始化只发生在对象创建的时候,而对象创建的时候会调用构造函数
构造函数的执行又俩个阶段
1.初始化阶段:无论成员变量是否在初始化列表中,都会进行初始化
2.赋值阶段:根据函数体里面内容进行赋值
因为他们三必须创建的时候就进行初始化!!!
首先const类型的变量和引用类型都必须进行初始化操作,否则会报错
B中有A类成员,要先创建B中的成员变量,调用B的构造函数,然后再对B中的成员变量进行赋值
先调用类成员的构造函数,再调用本类的构造函数,最后先调用本类的析构函数,再调用类成员的析构函数
不能调用构造函数初始化,因为构造函数归类所有,不是对象所有
静态成员变量的初始化和全局变量的初始化
因为有类型的内存叫类,所以要是类里面啥也没有就给它一个1字节大小
1.因为有const,所以常对象里面的成员变量的值不能修改
2.常对象只能调用常函数
3.非常对象优先调用非常函数,若无非常函数,再调用常函数
1.常函数有this指针,但是类型是常指常类型,无法修改对象里面的成员变量的值,也不能调用非常函数
2.常函数与非常函数会发生函数重载
如果有俩个函数,它的函数名和参数均相同,什么情况下会发生函数重载?
在这俩个函数一个是常函数,一个是非常函数的时候会发生函数重载,因为编译器会根据对象是否是常对象,来调用不同的函数。
3.成员变量在声明的时候前面加mutable,就可以在常函数中修改其值
4.常函数只能再类中定义,出了类定义是错误的
5.常函数不能调用非常函数,因为常函数的this指针为常指常,而非常函数的this指针为指常,类型不兼容
告诉我想访问的那个类,我是你们这个类的我的好朋友,可以让我访问私有成员属性
友元除了前面讲过的函数以外,友元还可以是类,即一个类可以作另一个类的友元。当一个类作为另一个类的友元时,这就意味着这个类的所有成员函数都是另一个类的友元函数。
当一个函数是另外一个类的友元函数的时候,那么它就可以访问另一个类的私有成员变量
1.对象调用get set函数
2.把一个类和全局函数设置为友元
作用:实现俩个自定义运算符相加
可以少传递一个参数
和访问权限一样,同样有三种
父类中如果有private类型的成员,无论以何种继承方式,都无法在子类中访问
虽然是无法访问,但是它仍旧被继承了过来,只是被隐藏了,仍然占用子类的空间
当创建子类对象的时候,会优先调用父类的构造函数,然后调用子类的构造函数
为什么?
因为子类对象需要先继承父类的成员变量,也就是先创建父类的成员变量,然后要对父类对象赋值,所以调用父类构造函数,然后再创建自己的成员变量,调用自己的构造函数
入栈出栈顺序有关
静态成员变量俩种调用方式,作用域和对象名调用
但是无论是哪种调用,再同名静态成员变量继承中,都要加上作用域
同样存在二义性但是与多击沉不同可以通过virtual来解决,也可以通过作用域解决