C++笔记

   日期:2024-12-26    作者:fjsygz 移动:http://mip.riyuangf.com/mobile/quote/35365.html

在C中要想输入和输出 我们会经常用到

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来解决,也可以通过作用域解决


特别提示:本信息由相关用户自行提供,真实性未证实,仅供参考。请谨慎采用,风险自负。


举报收藏 0评论 0
0相关评论
相关最新动态
推荐最新动态
点击排行
{
网站首页  |  关于我们  |  联系方式  |  使用协议  |  隐私政策  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  鄂ICP备2020018471号