c++基础内容,快速了解知识点,基础基础基础

C++

引用

1.概念:

引用是为已存在的变量取一个别名,引用与引用的变量共用一块内存空间。

2.特性

1.引用实体与引用类型必须为同种类型。

2.引用在被定义时必须被初始化,并且不能被初始化为空。

3.引用关系不能被改变

3.被const修饰的变量,其引用也要被const修饰。

4.用法

函数参数

直接在函数内部对参数进行修改

提高运行效率

函数返回值

在内存中不产生被返回值的副本

5.引用和指针的区别

指针有自己的一块空间,而引用只是一个别名

使用 sizeof 看一个指针的大小是4而引用则是被引用对象的大小

指针和引用使用++运算符的意义不一样,指针自增时指针上的运算,引用自增是+1

有多级指针没有多级引用

没有空引用但有空指针

指针需要显式解引用,引用编译器自己处理

函数重载(重点)

1.概念:相同作用域,函数名相同,参数列表不同,参数列表不同具体体现在参数类型不同、个数不同以及类型次序不同,与返回值类型是否相同无关

2.调用原理(重载决策):编译器通过对实参类型进行推演,根据推演的结果找对应的重载函数,如果存在且不会造成二义性则调用,否则产生编译错误

考点

1.什么是函数重载?

2.函数重载如何确定到底应该调用那个函数?编译期间还是运行期间?

3.函数重载如何确定到底应该调用那个函数?编译期间还是运行期间?

C++编译器对函数名字修饰规则:编译器将参数类型信息增加到名字中了,这样即使函数名相同,只要参数类型不同,其在底层的名字就不同,编译器根据所传递参数在编译期间就可以确定到底应该调用那个函数

4.如果两个函数仅仅是因为返回值不同,为什么不能形成重载?

不能,比如:两个Add函数,参数都是int类型,一个返回int,一个返回double,如果按照Add(1,2),应该调用那个重载函数呢,编译器就无法通过参数来确定了,因此报错

动态内存

new

new和malloc区别

(1)new是操作符,而malloc是函数。
(2)new在调用的时候先分配内存,再调用构造函数,释放的时候调用析构函数;而malloc没有构造函数和析构函数。
(3)malloc需要给定申请内存的大小,返回的指针需要强转;new会调用构造函数,不用指定内存的大小,返回指针不用强转。malloc默认返回类型是void*。
(4)new可以被重载;malloc不行。
(5)new分配内存更直接和安全。
(6)new发生错误抛出异常,malloc返回null。

delete

delete和delete[]区别

对于自定义类型来说,就需要对于单个对象使用delete,对于对象数组使用delete [],逐个调用数组中对象的析构函数,从而释放所有内存;
如果反过来使用,即对于单个对象使用delete [],对于对象数组使用delete,其行为是未定义的;所以,最恰当的方式就是如果用了new,就用delete;如果用了new [],就用delete []

运算符重载

1.用法:返回值 operator 需要重载的运算符

2.常见的运算符重载

赋值运算符重载


++和–重载
输入和输出运算符即(>>和<<)重载
[]运算符重载
*和->重载
()重载

3.注意事项

有int标识的是后++,没有的是前++

注意重载函数的返回值

不能重载的运算符(5个)

". " ," .*" "::" , "sizeof" ,"?:"
前2个不能被重载是保证能正常访问成员,域运算和sizeof不能被重载是因为运算对象是类而不是对象

只能使用成员函数重载(4个)

"="、"[]"、"->"和"()"只能通过成员函数重载是因为它们是与类的数据成员和成员函数相关的操作符

类和对象

1.面向对象和面向过程的区别

面向过程:根据业务逻辑从上到下写代码
面向对象:将数据与函数绑定到一起,进行封装,这样能够更快速的开发程序,减少了重复代码的重写过程

2.面向对象

面向对象三大特性

封装

1.概念:将属性和行为封装在一起表现为一个对象

2.访问限定符

1.private:修饰的成员只能被类内访问

2.protected:修饰的成员只能被类和子类访问

3.public:类内类外都能访问

继承

继承方式

private

protected

public

●凡是基类中私有的,派生类都不可访问。
●基类中除了私有的成员,其他成员在派生类中的访问属性总是以(继承方式,
基类的访问属性)中安全性高的方式呈现。(安全性级别: 私有>保护>公有)

多态

this指针

1.概念:一个对象的this指针并不是对象本身的一个部分,不会影响sizeof(对象)的结果。this作用域是在类内部,当在类的非静态成员函数中访问类的非静态成员函数的时候,编译器会自动将对象本身地址作为一个隐含参数传递给函数。

2.this是指向当前对象的指针,哪个对象调用包含this指针的函数,this指向哪个对象。

3.用法:this是指向当前对象的指针,哪个对象调用包含this指针的函数,this指向哪个对象。

构造函数

1.概念:构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员
都有 一个合适的初始值,并且在对象的生命周期内只调用一次。

2.特性

没有返回值 类名 (){ } 后面可以跟加初始化参数列表

函数名称和类名相同

构造函数可以有参数,可以重载

编译器在创建对象的时候会自动调用构造函数

3.种类

默认构造函数

默认构造函数和初始化构造函数。
在定义类的对象的时候,完成对象的初始化工作。
有了有参的构造函数,编译器就不提供默认的构造函数。

初始化构造函数

初始化参数列表

1.只有构造函数有初始化列表
2.必须初始化的成员放在初始化列表
3.在本对象构造之前需要完成的动作必须放在初始化列表中
4.const类型和引用类型 必须放在初始化列表中初始化

成员的构造顺序与初始化参数列表的顺序无关,与在类中声明顺序有关

拷贝构造函数(className (const className &obj))

1.概念:拷贝构造函数是构造函数的一种重载形式,它可以用来创建一个与已存在的对象一模一样的新对象。对于拷贝构造,它只有单个形参,且该形参必须是对本类类型对象的引用,因为要引用,所以要加const修饰。

2.使用场景:

1.使用一个已经存在的对象创建一个新的对象

2.对象作为函数的返回值以值的方式从函数返回

3.对象作为函数参数,以值传递的方式传给函数

3.深拷贝和浅拷贝

浅拷贝

又称值拷贝,将源对象的值拷贝到目标对象中去

编译器生成的拷贝构造函数是浅拷贝

深拷贝

拷贝的时候先开辟出和源对象大小一样的空间,然后将源对象里的内容拷贝到目标对象中去,这样两个指针就指向了不同的内存位置

移动构造函数(c++11)

析构函数

1.概念:与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成类的一些资源清理工作

2.特性

析构函数名是在类名前加上字符 ~

无参数无返回值

一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数,即析构函数不能重载

对象生命周期结束时,C++编译系统系统自动调用析构函数

基类的析构函数最好设置成虚函数

多态

分类

静态多态(早绑定,静态联编)

在编译阶段,编译器根据传递实参类型确定具体调用那个函数

函数模版->

函数重载->

动态多态(晚绑定、动态联编)

在运行时,根据基类指针或引用指向的不同类的对象,调用具体的虚函数

实现条件(两个条件缺一不可)

基类必须具有虚函数(被virtual关键字修饰的成员函数),并且派生类必须要对基类的虚函数进行重写

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

2.函数重写(覆盖)

概念

基类函数一定是虚函数
派生类虚函数必须要与基类虚函数原型完全一致,即:返回值类型相同 函数名相同(参数列表相同)
基类和派生类虚函数的访问权限可以不同

例外返回值协变时重写的返回值类型可以不同(父类返回父类指针或引用,子类返回子类的指针或引用)

3.函数隐藏

函数名相同,参数不同无论父类有没有virtual都是隐藏

4.多态的实现

虚表

每个包含虚函数的类都包含一个虚表(存放虚函数指针的数组)

一个类继承了包含虚函数的类,那么这个类也拥有自己的虚表

虚函数指针的赋值发生在编译器编译阶段,所以在编译阶段,虚表就存在了

虚表指针

虚表属于类不属于具体对象,一个类拥有一个虚表,同一类的所有对象共用一个虚表

为了指定对象的虚表,对象内部包含一个虚表的指针,来指向自己所使用的虚
表。为了让每个包含虚表的类的对象都拥有一个虚表指针, 编译器在类中添加
了一个指针,*_ _vptr, 用来指向虚表。这样,当类的对象在创建时便拥有了这.
个指针,且这个指针的值会自动被设置为指向类的虚表。

虚析构

抽象类

纯虚函数

在虚函数的后面写上 =0 ,则这个函数为纯虚函数

概念

包含纯虚函数的类叫做抽象类

特点

抽象类不能实例化对象,但是可以定义抽象类的指针或引用

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

模版/异常

模版

函数模版

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本

语法

template<typename T1, typename T2,…,typename Tn>
返回值类型 函数名(参数列表){}

模版类

异常

1.实现

throw:抛出异常
catch:按照类型捕获异常
try: 将可能抛出异常的代码放在try块中,注意:try之后必须跟catch对抛出的异常进行捕获

2.异常的抛出

异常不是直接将异常对象抛出去,抛出的是一个副本
异常是按照类型进行捕获的,一般情况下不会进行类型转化
距离异常抛出位置进行的匹配捕获先捕获到异常
工程实现时一般都是通过自定义异常类来进行异常的抛出和捕获的,具体错误抛出具体的类型异常对象,然后捕获位置使用基类的引用来进行捕获

内联

1.概念

以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,
内联函数提升程序运行的效率。

2.特性

1.inline是一种用空间换时间的做法,省去调用函数开销,所以代码很长或者有循环/递归的函数不适宜使用作为内联函数

2.inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等
等,编译器优化时会忽略掉内联

3.inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会
找不到。

宏函数

优点

在预处理阶段会展开,少了函数调用参数压栈等的开销

缺点

在预处理阶段展开,增加了预处理时间
编译之前已经展开了,如果编译时报错,错误不好定位
参数没有类型,而缺编译时已经展开,不能进行参数类型检测,安全性低
可读性比较差,比如:为了保证参数的正确性,需要多出加括号,但仍旧可能会引起副作用。
不能调试
因为要已经展开,如果调用的位置比较多,可能会引体代码膨胀

内联函数优/缺

优点

是一个函数,参数具有类型,可以进行类型检测,安全性高
在编译阶段展开,少了函数调用开销,能够提高代码运行效率
是函数,在调试时可以不让编译器展开,方便调试

缺点

可能会引起代码膨胀
inline是建议性关键字,即建议编译器将inline修饰的函数按照内联函数处理,但是编译器是否真正会将其当成内联函数处理,则不一定,容易给用户造成困然

友元/常函数

友元

1.概念

友元定义在类的外部,友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声
明,声明时需要加friend关键字

2.特性

友元函数可访问类的私有和保护成员,但不是类的成员函数
友元函数不能用const修饰
友元函数可以在类定义的任何地方声明,不受类访问限定符限制
一个函数可以是多个类的友元函数
友元函数的调用与普通函数的调用和原理相同

友元优/缺

优点:提高效率,表达简单清晰

缺点:破坏了封装的机制,不建议使用

常函数

1.概念:在类成员函数后面加const,表示该函数不会对这类非静态的成员变量进行改变。

2.特性

实际修饰的是函数隐藏的this指针
在该类中不能修改对象中任何成员变量,除非该变量使用nutable修饰
该成员函数中:只能调用const成员函数,不能调用普通成员函数

静态成员

静态成员变量

1.概念:类的静态成员变量在类内声明,类外定义初始化,内存分配在全局区,静态成员变量不属于类的对象,而属于整个类

2.特性

1.静态成员变量不能在初始化列表位置初始化,必须在类外进行初始化,在类外初始化时必须要加类名::,类中只是声明

2.静态成员变量属于整个类,所有对象共享一个静态成员变量

3.可以通过类名或对象名访问公有的静态成员变量

4.存放在全局静态区,生命周期不依赖任何对象,与程序的生命周期一致

5.静态成员变量不会被继承,父类和子类共享静态成员变量

6.静态成员变量不影响类的大小

静态成员函数

特性

静态成员函数没有this指针。
静态成员函数中不能直接访问非静态成员变量,因为所有非静态成员变量都是通过this指针访问的。
静态成员函数中不能调用普通成员函数,可以调用静态成员变量和静态成员函数。
静态成员函数不能被this修饰静态成员函数不能是虚函数。
可以通过类名和对象访问公有的静态成员函数。

设计模式

单例模式

工厂模式

简单工厂模式

抽象工厂模式

享元模式

C++11

创建派生类的对象时,基类对象首先被创建,然后再调用派生类的构造函数

考点:
C/C++程序将内存分为了那些区?为什么要进行分区?
不同类型的变量在那些区?每个区大概作用
malloc/calloc/realloc的区别?
malloc函数的实现原理
new和delete的实现原理

考点:
解释下static关键字的作用
什么是静态成员函数?和普通成员函数的区别?
静态成员函数中能调用非静态成员函数吗?为什么?
静态成员函数能用const修饰吗?为什么?(不能)
静态成员函数能设置成虚函数吗?为什么

●虚析构:将可能被继承的父类的析构函数设置为虚函数,可以保证当我们new一个子类,然后使用基类指针指向该子类对象,释放基类指针时可以释放掉子类的空间,防止内存泄漏。如果基类的析构函数不是虚函数,在特定情况下会导致派生类无法被析构。(先释放子类后释放父类)
1.用派生类类型指针绑定派生类实例,析构的时候,不管基类析构函数是不是虚函数,都会正常析构。
2.用基类类型指针绑定派生类实例,析构的时候,如果基类析构函数不是虚函数,则只会析构基类,不会析构派生类对象,从而造成内存泄漏。
●C++默认的析构函数不是虚函数是因为虚函数需要额外的虚函数表和虚表指针,占用额外的内存。而对于不会被继承的类来说,其析构函数如果是虚函数,就会浪费内存。因此C++默认的析构函数不是虚函数,而是只有当需要当作父类时,设置为虚函数。

考点:
什么是多态?
什么是重载、重写(覆盖)、重定义(隐藏)?
多态的实现原理?
inline函数可以是虚函数吗?
静态成员可以是虚函数吗?
构造函数可以是虚函数吗?
析构函数可以是虚函数吗?什么场景下析构函数是虚函数?
多态的缺陷
虚函数表是在什么阶段生成的,存在哪的?
同一个类的不同对象,使用的是同一张虚表吗?
一个类的对象可以包含多张虚表吗?
什么是抽象类?抽象类的作用?

如果类中包含有虚函数,对象中将会多4个字节,在对象前4个字节中保存虚表的地址

考点:
解释下什么是this指针
this指针存放在哪里?
this指针有没有可能是NULL?
常见的调用约定有那些?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值