C/C++笔试易错与高频题型图解知识点(二)—— C++部分(持续更新中)

目录

1.构造函数初始化列表

1.1 构造函数初始化列表与函数体内初始化区别

1.2 必须在初始化列表初始化的成员

2 引用&引用与指针的区别

2.1 引用初始化以后不能被改变,指针可以改变所指的对象

 2.2 引用和指针的区别

3 构造函数与析构函数系列题

3.1构造函数与析构函数的调用次数

4 类的运算符重载

5 类的静态数据成员

5.1 malloc/new/new[]

5.2 new的实现步骤与细节

6 this指针相关题目 

6.1 this可以为空吗?

6.2 this指针存放在哪里?

6.3 delete this

7 其他于类相关的题目

7.1 空类的大小

7.2 对const变量的修改

  volatile

 7.3 赋值运算符重载



1.构造函数初始化列表

有一个类A,其数据成员如下: 则构造函数中,成员变量一定要通过初始化列表来初始化的是:______。

class A {
...
private:int a;
public:const int b;float* &c;static const char* d;static double* e;
};

A. a b c

B. b c

C. b c d e

D. b c d

E. b

F. c

答案:B

知识点:

1.1 构造函数初始化列表与函数体内初始化区别

一个类,其包含一个类类型成员,对于它的构造函数,如果在函数体内初始化,会先调用其类类型成员的默认构造函数,在调用赋值运算符,而在构造函数初始化时会直接调用它的拷贝构造函数进行初始化

函数体类初始化:

#include <iostream>class B {
public:B() { std::cout << "B defualt construct" << '\n'; }B(int t) : _t(t) { std::cout << "B construct" << '\n'; }B(const B& b) : _t(b._t) { std::cout << "B copy construct" << '\n'; }B& operator=(const B& b) {_t = b._t;std::cout << "B assign operator"<< '\n';return *this;}
private:int _t = 0;
};
class A {
public:A() { std::cout << "A defualt construct" << '\n'; }A(const B& b){ puts("---------------------");_b = b;std::cout << "A construct" << '\n'; }A(const A& a) : _b(a._b) { std::cout << "A copy construct" << '\n'; }A& operator=(const A& a) {_b = a._b;std::cout << "A assign operator" << '\n';return *this;}
private:B _b;
};
int main() {B b(1);A a(b);
}

初始化列表初始化:

#include <iostream>class B {
public:B() { std::cout << "B defualt construct" << '\n'; }B(int t) : _t(t) { std::cout << "B construct" << '\n'; }B(const B& b) : _t(b._t) { std::cout << "B copy construct" << '\n'; }B& operator=(const B& b) {_t = b._t;std::cout << "B assign operator"<< '\n';return *this;}
private:int _t = 0;
};
class A {
public:A() { std::cout << "A defualt construct" << '\n'; }A(const B& b) : _b(b) { puts("---------------------");std::cout << "A construct" << '\n';}/*A(const B& b){ puts("---------------------");_b = b;std::cout << "A construct" << '\n'; }*/A(const A& a) : _b(a._b) { std::cout << "A copy construct" << '\n'; }A& operator=(const A& a) {_b = a._b;std::cout << "A assign operator" << '\n';return *this;}
private:B _b;
};
int main() {B b(1);A a(b);
}

1.2 必须在初始化列表初始化的成员

• const修饰的成员变量

• 引用类型成员

• 类类型成员,且该类没有默认构造函数(由1.1内容可得)

2 引用&引用与指针的区别

2.1 引用初始化以后不能被改变,指针可以改变所指的对象

int main() {int a = 10;int& ref = a;     int b = 20;    ref = b;std::cout << "a:" << a << " ref:" << ref << " b:" << b; //output:a:20 ref:20 b:20
}

 2.2 引用和指针的区别

引用和指针,下面说法不正确的是()

A. 引用和指针在声明后都有自己的内存空间

B. 引用必须在声明时初始化,而指针不用

C. 引用声明后,引用的对象不可改变,对象的值可以改变,非const指针可以随时改变指向的对象以及对象的值

D. 空值NULL不能引用,而指针可以指向NULL

答案:A

#include <iostream>int main() {int a = 10;int& ref = a;std::cout << "a:" << &a << '\n' << "ref:" << &ref << '\n';//a:00FCF8D4     ref:00FCF8D4int b = 10;int* ptr = &b;std::cout << "b:" << &b << '\n' << "ptr:" << &ptr << '\n';//b : 00FCF8BC     ptr: 00FCF8B0return 0;
}

 从定义内存上看,引用和被引用变量公用同一块空间

3 构造函数与析构函数系列题

3.1构造函数与析构函数的调用次数

1)

C++语言中,类ClassA的构造函数和析构函数的执行次数分别为()

ClassA *pclassa=new ClassA[5];
delete pclassa;

A. 5,1

B. 1,1

C. 5,5(错误)

D. 1,5

答案:A 

2)

#include <iostream>
#include <string>
using namespace std;
class Test {
public:Test(){ std::cout << this << "B defualt construct" << '\n'; }~Test() { std::cout << this <<   "B destory" << '\n'; }
};
int main() {Test t1;puts("------------");Test* t2;puts("------------");Test t3[3];puts("------------");Test* t4[3];        //t4是存放三个类型Test*的对象的数组puts("------------");Test(*t5)[3];       //t5是数组指针,指向一个存放三个类型为Test的对象的数组puts("------------");
}

 打印结果:

4 类的运算符重载

在重载一个运算符为成员函数时,其参数表中没有任何参数,这说明该运算符是 ( )。

A. 无操作数的运算符

B. 二元运算符

C. 前缀一元运算符

D. 后缀一元运算符(错误)

答案:C

例如:

前置++:T& operator++() {} 

后置++:T operator++(int) {}

5 类的静态数据成员

下面有关c++静态数据成员,说法正确的是()

A. 不能在类内初始化(错误)

B. 不能被类的对象调用

C. 不能受private修饰符的作用

D. 可以直接用类名调用  

答案:D : 

知识点:const修饰的静态成员可以在类内初始化,所以A错误

5.1 malloc/new/new[]

malloc/calloc/realloc <----> free        new <----> delete        new [] <----> delete[]三者一定要匹配使用,否则会产生内存泄漏或者程序崩溃

5.2 new的实现步骤与细节

1) 对于 T*p = new T;

-第一步: 调用operator new(size_t size)申请空间(内部调用malloc循环申请)

-第二步: 调用构造函数完成对申请空间的初始化

     对于 delete p;

-第一步:调用析构函数释放p指向的对象中的资源

-第二步:调用operator delete释放p所指向的空间(内部调用free)

2)对于 T*p = new T[N];

-第一步: 调用operator new[](size_t size)申请空间(内部调用operator new(size_t size))

-第二步: 调用N次T的构造函数完成对申请空间的初始化

     对于 delete p;

-第一步:调用N次T的析构函数释放p指向的N个对象中的资源

-第二步:调用operator delete[]释放p所指向的空间(内部调用operator delete)

6 this指针相关题目 

6.1 this可以为空吗?

6.2 this指针存放在哪里?

6.3 delete this 以及 delete细节解析

如果有一个类是 myClass , 关于下面代码正确描述的是:

myClass::~myClass(){delete this;this = NULL;
}

A. 正确,我们避免了内存泄漏

B. 它会导致栈溢出

C. 无法编译通过                            

D. 这是不正确的,它没有释放任何成员变量。(错误) 

答案:C

对于上述代码,首先它是不能被编译通过的,因为this指针本身被const修饰(对于上述例子而言this指针的类型为myClass *const), this指针本身无法被修改

如果删去`this = NULL`这一段代码,程序还是有错,我们通过下面几个例子说明⬇️

首先我们需要了解:调用delete函数之后会依次执行下面两个步骤 

① 对目标调用的析构函数

② 调用operator delete释放内存

通过下面几种了解:

1)

#include <iostream>
using namespace std;class Test {
public:Test() {puts("Test()");x = 0;ptr = new int(0);}~Test() {puts("~Test() before");delete this;//this = nullptr;   //编译错误	C2106“ = ”: 左操作数必须为左puts("~Test() after");}
private:int x;int* ptr;
};int main() {Test t;
}

 上面这段代码执行会不断打印~Test() before,直至程序栈溢出

解释了调用operator delete之后的执行步骤,上述代码会this指针指向对象的析构函数,而析构函数中又有delete函数,导致死循环,如下图⬇️

2)

#include <iostream>
using namespace std;class Test2 {
public:Test2() {ptr = new int(0);}~Test2() {puts("~Test2");delete ptr;ptr = nullptr;}void deletefunc() {delete this;   //先析构,再delete this指向的堆空间(当this指向的是栈上的空间时,程序崩溃)}
private:int* ptr;int x = 0;
};
int main() {Test2* tptr = new Test2();tptr->deletefunc();
}

通过上述代码和动画演示巩固delete的两个步骤;

如过将对象创建再栈中,上述程序又会出现bug:编译阶段不会报错,但是再运行到delete this的时候程序崩溃了,原因是对栈上的空间进行了释放

	Test2 obj = Test2();obj.deletefunc();

3)

#include <iostream>
using namespace std;void operator delete(void* ptr) {     puts("operator delete");
}
class Test2 {
public:Test2() {ptr = new int(0);}~Test2() {puts("~Test2");delete ptr;ptr = nullptr;}void deletefunc() {delete this;   }
private:int* ptr;int x = 0;
};
int main() {Test2* ptr = new Test2();ptr->deletefunc();
}

调试上述代码

 

7 其他于类相关的题目

7.1 空类的大小

在Windows 32位操作系统中,假设字节对齐为4,对于一个空的类A,sizeof(A)的值为()? A. 0

B. 1

C. 2

D. 4(错误)

答案:B

类大小的计算方式:与结构体大小的计算方式类似,将类中非静态成员的大小按内存对齐规则计算,并且不用计算成员函数;

特别的,空类的大小在主流的编译器中设置成了1

7.2 对const变量的修改

以下程序输出是____。

#include <iostream>
using namespace std;
int main(void)
{const int a = 10;int * p = (int *)(&a);*p = 20;cout<<"a = "<<a<<", *p = "<<*p<<endl;return 0;
}

A. 编译阶段报错运行阶段报错

B. a = 10, *p = 10

C. a = 20, *p = 20(错误)

D. a = 10, *p = 20

E. a = 20, *p = 10

 答案:D

知识点:

1)编译器在编译阶段会对const修饰的变量进行优化,将其替换成变量的值

由图中的汇编代码可以看到,打印变量a时,他被直接替换成了10这个常量

  volatile

C/C++ 中的 volatile 关键字和 const 对应,用来修饰变量,volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

#include <iostream>
using namespace std;
int main(void)
{const int volatile a = 10;int* p = (int*)(&a);*p = 20;cout << "a = " << a << ", *p = " << *p << endl;return 0;
}

当用volatile修饰a之后打印结果为:

 7.3 赋值运算符重载

下列关于赋值运算符“=”重载的叙述中,正确的是

A. 赋值运算符只能作为类的成员函数重载

B. 默认的赋值运算符实现了“深层复制”功能

C. 重载的赋值运算符函数有两个本类对象作为形参(错误)

D. 如果己经定义了复制拷贝构造函数,就不能重载赋值运算符

答案:A

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/161140.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VScode platformio的使用

一、platformio 工程创建 打开vscode界面你会发现左下多了个家的小图标&#xff0c;点击这里就可以进入platformio。 在右侧Quick Access栏中&#xff0c;有4个选项。可以看得出来&#xff0c;我们这里直接点击创建一个新的工程。 点击New Project打开project配置界面&#x…

图详解第四篇:单源最短路径--Dijkstra算法

文章目录 1. 最短路径问题2. 单源最短路径--Dijkstra算法算法思想图解如何存储路径及其权值代码实现调式观察打印最短路径Dijkstra算法的缺陷 3. 源码 1. 最短路径问题 最短路径问题&#xff1a; 从带权有向图&#xff08;求最短路径通常是有向图&#xff09;G中的某一顶点出发…

Unity——数据存储的几种方式

一、PlayerPrefs PlayerPrefs适合用于存储简单的键值对数据 存储的数据会在游戏关闭后依然保持&#xff0c;并且可以在不同场景之间共享&#xff0c;适合用于需要在游戏不同场景之间传递和保持的数据。 它利用key-value的方式将数据保存到本地&#xff0c;跟字典类似。然后通…

【排序算法】详解直接插入排序和希尔排序原理及其性能分析

文章目录 插入排序算法原理细节分析代码实现复杂度分析:稳定性分析:与冒泡排序的对比 希尔排序算法原理细节分析代码实现复杂度分析稳定性分析 总结对比 插入排序 算法原理 插入排序又或者说直接插入排序,是一种和冒泡排序类似的并且比较简单的排序方法&#xff0c; 基本思想…

android aidl Can‘t resolve Salary问题

** 解决方法 ** 在数据aidl中写上包名&#xff0c;并且保证他的实体类也应当在与数据aidl文件相同的java类的包下 如果实例类放在aidl文件中会报一些稀奇古怪的错误&#xff0c;可以生成.java文件但是里面的实体类是不能识别的

Swagger使用

Swagger 简介 号称世界上最流行的API框架&#xff1b;Restful API 文档在线生成工具 —> API文档与API定义同步更新直接运行&#xff0c;可以在线测试 API 接口&#xff1b;支持各种语言&#xff1b;&#xff08;Java&#xff0c;PHP…&#xff09; 官网 Spring Boot 集…

BUUCTF学习(5): 命令执行Ping

1、介绍 2、解题 127.0.0.1|cat /flag 结束

Unity-3D模型展示

将3D模型放置到某个位置&#xff0c;然后通过鼠标左键进行旋转的操作 一种方法是添加另外的相机&#xff0c;采用RenderTexture来渲染该相机的内容 那么RenderTexture是做什么的呢&#xff1f; RenderTexture可以捕获从摄像机、光源和其他对象渲染的图像&#xff0c;并将结果…

如何使用FME开发自动化分析报告功能

目录 前言 一、使用的技术栈 二、技术难点解析 1.专题图 2.WORD文档实现 2.1 动态标题 2.3动态表格和文本 2.3专题图插入 三、完成NewGIS部署 四、模板总览图 总结 前言 一个标准项目分析报告需要需要包括3个方面&#xff1a; 文本叙述&#xff0c;主要体现在对某项专项数据的…

cmd进程简单操作指令

dir 查询当前路径和子路径 start空格加自己的exe程序&#xff0c;可运行程序。 taskkill /?可以执行很多&#xff0c;通常用于结束程序。 taskkill /f /im qq.exe 启动nginx.exe 查看运行的进程有哪些 选择结束nginx.exe

Python文件共享+cpolar内网穿透:轻松实现公网访问

文章目录 1.前言2.本地文件服务器搭建2.1.Python的安装和设置2.2.cpolar的安装和注册 3.本地文件服务器的发布3.1.Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 数据共享作为和连接作为互联网的基础应用&#xff0c;不仅在商业和办公场景有广泛的应用&#…

数据结构----算法--五大基本算法

数据结构----算法–五大基本算法 一.贪心算法 1.什么是贪心算法 在有多个选择的时候不考虑长远的情况&#xff0c;只考虑眼前的这一步&#xff0c;在眼前这一步选择当前的最好的方案 二.分治法 1.分治的概念 分治法&#xff1a;分而治之 将一个问题拆解成若干个解决方式…

uni-app--》基于小程序开发的电商平台项目实战(六)

&#x1f3cd;️作者简介&#xff1a;大家好&#xff0c;我是亦世凡华、渴望知识储备自己的一名在校大学生 &#x1f6f5;个人主页&#xff1a;亦世凡华、 &#x1f6fa;系列专栏&#xff1a;uni-app &#x1f6b2;座右铭&#xff1a;人生亦可燃烧&#xff0c;亦可腐败&#xf…

docker入门加实战—docker常见命令

docker入门加实战—docker常见命令 在介绍命令之前&#xff0c;先用一副图形象的展示一下docker的命令&#xff1a; 常见命令 docker的常见命令和文档地址如下表&#xff1a; 命令说明文档地址docker pull拉取镜像docker pulldocker push推送镜像到DockerRegistrydocker pus…

EmoTalk: Speech-Driven Emotional Disentanglement for 3D Face Animation

问题:现存的方法经常忽略面部的情感或者不能将它们从语音内容中分离出来。 方法:本文提出了一种端到端神经网络来分解语音中的不同情绪,从而生成丰富的 3D 面部表情。 1.我们引入了情感分离编码器(EDE),通过交叉重构具有不同情感标签的语音信号来分离语音中的情感和内容。…

【广州华锐互动】塔吊多人安拆VR互动培训系统

塔吊多人安拆VR互动培训系统由广州华锐互动制作&#xff0c;是一种基于VR技术的模拟实训系统&#xff0c;专门用于培训塔吊驾驶员和操作员。 在现实生活中&#xff0c;塔吊操作具有一定的危险性&#xff0c;尤其是在培训过程中容易发生意外。而使用VR互动实训系统&#xff0c;学…

金融用户实践|分布式存储支持数据仓库业务系统性能验证

作者&#xff1a;深耕行业的 SmartX 金融团队 闫海涛 估值是指对资产或负债的价值进行评估的过程&#xff0c;这对于投资决策具有重要意义。每个金融公司资管业务人员都期望能够实现实时的业务估值&#xff0c;快速获取最新的数据和指标&#xff0c;从而做出更明智的投资决策。…

Java8实战-总结42

Java8实战-总结42 用Optional取代null应用 Optional 的几种模式默认行为及解引用 Optional 对象两个 Optional 对象的组合使用 filter 剔除特定的值 用Optional取代null 应用 Optional 的几种模式 默认行为及解引用 Optional 对象 采用orElse方法读取这个变量的值&#xff0…

uniapp订单循环列表倒计时

目录 效果图片插件uni-countdown代码最后 效果图片 插件uni-countdown 地址 代码 <template><view class""><!-- 下面循环两个列表 --><view class"item" v-for"(item, index) in listData" :key"index">&…

mybatis-plus自动填充

前言 这是我在这个网站整理的笔记&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 mybatis-plus自动填充 大家做设计数据表的时候&#xff0c;基本上都会有del_flag&#xff0c;create_time, update_time,这三个字段&#xff0c;这也是…