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.mzph.cn/news/108537.shtml

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

相关文章

【LeetCode热题100】--287.寻找重复数

287.寻找重复数 方法&#xff1a;使用快慢指针 使用环形链表II的方法解题&#xff08;142.环形链表II&#xff09;&#xff0c;使用 142 题的思想来解决此题的关键是要理解如何将输入的数组看作为链表。 首先明确前提&#xff0c;整数的数组 nums 中的数字范围是 [1,n]。考虑一…

【Qt控件之QDialogButtonBox】概述及使用

概述 QDialogButtonBox类是一个小部件&#xff0c;它以适合当前小部件样式的布局呈现按钮。 对话框和消息框通常以符合该台界面指南的布局呈现按钮。不同的平台会有不同的对话框布局。QDialogButtonBox允许发人员向其添加按钮&#xff0c;并将自使用用户的桌面环境所适合的布局…

数据结构--堆

一. 堆 1. 堆的概念 堆&#xff08;heap&#xff09;&#xff1a;一种有特殊用途的数据结构——用来在一组变化频繁&#xff08;发生增删查改的频率较高&#xff09;的数据集中查找最值。 堆在物理层面上&#xff0c;表现为一组连续的数组区间&#xff1a;long[] array &…

MySQl_2

目录 函数 一.字符串函数 二.数值函数 三.日期函数 四.流程控制函数 约束 多表查询 多表关系 一.内连接 二.外连接 三.自连接 四.联合查询 五.子查询 标量子查询 列子查询 行子查询 表子查询 函数 一.字符串函数 二.数值函数 SELECT LPAD(FLOOR(RAND()*1000000),…

二叉树与递归的相爱相杀

数据结构之二叉树 一、基于二叉树的基础操作1.二叉树的构建2.二叉树的遍历①前序遍历&#xff08;深度遍历&#xff09;②中序遍历③后序遍历④层序遍历判断一棵二叉树是否是完全二叉树&#xff08;基于层序遍历的思想&#xff09; 3.二叉树的数量问题①求二叉树结点个数②求二…

PixMIM论文笔记

论文名称&#xff1a;PixMIM: Rethinking Pixel Reconstruction in Masked Image Modeling 发表时间&#xff1a;2023 年 3 月 4 日 作者及组织&#xff1a;上海人工智能实验室、西蒙菲莎大学、香港中文大学 GitHub&#xff1a;https://github.com/open-mmlab/mmselfsup/tree/d…

transformer_01

一、传统RNN存在的问题 1.序列前序太长&#xff0c;每个xi要记住前面的特征&#xff0c;而且一直在学&#xff0c;没有忘记&#xff0c;可能特征不能学的太好 2.串行&#xff0c;层越多越慢&#xff0c;难以堆叠很多层&#xff1b; 3.只能看到过去&#xff0c;不能看到未来 搞…

什么是NetApp的DQP和如何安装DQP?

首先看看什么是DQP&#xff0c;DQPDisk Qualification Package&#xff0c;文字翻译就是磁盘验证包。按照NetApp的最佳实践&#xff0c;要定期升级DQP包&#xff0c;保证对最新磁盘和磁盘扩展柜的兼容。 本文主要介绍7-mode下如何升级DQP&#xff0c;至于cluster mode另外文章…

Linux Zabbix企业级监控平台+cpolar实现远程访问

文章目录 前言1. Linux 局域网访问Zabbix2. Linux 安装cpolar3. 配置Zabbix公网访问地址4. 公网远程访问Zabbix5. 固定Zabbix公网地址 前言 Zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。能监视各种网络参数&#xff0c;保证服务器系…

基于边缘网关构建水污染监测治理方案

绿水青山就是金山银山&#xff0c;生态环境才是人类最宝贵的财富。但是在日常生活生产中&#xff0c;总是免不了各种污水的生产、排放。针对生产生活与环境保护的均衡&#xff0c;可以借助边缘网关打造环境污水监测治理体系&#xff0c;保障生活与环境的可持续性均衡发展。 水污…

NewStarCTF2023week2-Upload again!

尝试传修改后缀的普通一句话木马&#xff0c;被检测 尝试传配置文件 .htaccess 和 .user.ini 两个都传成功了 接下来继续传入经过修改的木马 GIF89a <script language"php"> eval($_POST[cmd]); </script> 没有被检测&#xff0c;成功绕过 直接上蚁剑…

微查系统,一站式查询,让您的查询更加便捷

微查系统是挖数据一款功能强大的查询系统&#xff0c;是一个集多种查询和核验工具于一身的综合性平台。它可以大大简化企业和个人的查询流程&#xff0c;节省时间和成本&#xff0c;提高查询的准确性和效率。本文将介绍微查系统的主要特点&#xff0c;功能和使用方法&#xff0…

C++数据结构X篇_15_求二叉树叶子数与高度(递归方法)

本篇参考求二叉树叶子数与高度&#xff08;C&#xff09;进行整理。 文章目录 1. 二叉树中叶子数与高度2. 求二叉树叶子数与高度的实现代码 1. 二叉树中叶子数与高度 我们首先来看一看二叉树中叶子数与高度的定义&#xff1a; 叶子数&#xff1a;对于一个二叉树的节点&#x…

新型的终端复用器 tmux

以前遇到长时间执行任务时&#xff0c;一般是使用nohup加后台运行&#xff0c;但是涉及到少量代码编写。 同事介绍了一个screen命令&#xff0c;根据文档&#xff0c;此命令已经过时&#xff0c;最新的命令是tmux。 tmux的介绍文档&#xff0c;RedHat的这一篇非常不错。 在文…

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

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

linux下的rsync(文件同步) 用法教程

一、简介 rsync 是一个常用的 Linux 应用程序&#xff0c;用于文件同步。 它可以在本地计算机与远程计算机之间&#xff0c;或者两个本地目录之间同步文件&#xff08;但不支持两台远程计算机之间的同步&#xff09;。它也可以当作文件复制工具&#xff0c;替代cp和mv命令。 …

BIO实战、NIO编程与直接内存、零拷贝深入剖析

原生 JDK 网络编程 BIO BIO&#xff0c;意为 Blocking I/O&#xff0c;即阻塞的 I/O。   BIO 基本上就是我们上面所说的生活场景的朴素实现。在 BIO 中类 ServerSocket 负责绑定 IP 地址&#xff0c;启动监听端口&#xff0c;等待客户连接&#xff1b;客户端 Socket 类的实例…

SpringMVC源码分析(三)HandlerExceptionResolver启动和异常处理源码分析

问题&#xff1a;异常处理器在SpringMVC中是如何进行初始化以及使用的&#xff1f; Spring MVC提供处理异常的方式主要分为两种&#xff1a; 1、实现HandlerExceptionResolver方式&#xff08;HandlerExceptionResolver是一个接口&#xff0c;在SpringMVC有一些默认的实现也可以…

【算法练习Day22】 组合总和 III电话号码的字母组合

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 组合总和 III剪枝 电话号码…

node 通过axios发送post请求(FormData)

方案一&#xff1a; const axios require(axios) const FormData require(form-data) const fs require(fs)const sdUpscaleOnAzure async (req, res) > {const data new FormData()data.append(image, fs.readFileSync(/temp/ai/sd/download/1.png))let config {hea…