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,一经查实,立即删除!

相关文章

2023大联盟6比赛总结

比赛链接 反思 A 为什么打表就我看不出规律&#xff01;&#xff01;&#xff01; 定式思维太严重了T_T B 纯智障分块题&#xff0c;不知道为什么 B 100 B100 B100 比理论最优 B 300 B300 B300 更优&#xff08;快了 3 倍&#xff09;&#xff0c;看来分块还是要学习一…

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

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

VScode无法跳转函数定义

VScode需要在当前工作环境下解析函数之间的依赖关系&#xff0c;如果工作环境是根目录/&#xff0c;扫描的文件范围会比/home/username/code大很多&#xff0c;导致VScode无法解析出函数依赖&#xff0c;也就无法跳转。 解决办法&#xff1a;将路径目录从高目录调整到较低的目…

【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另外文章…

gazebo各种插件

类别 libgazebo_ros_api_plugin.so&#xff1a;提供与Gazebo仿真环境进行通信的API接口。 libgazebo_ros_block_laser.so&#xff1a;模拟激光传感器的插件。 libgazebo_ros_bumper.so&#xff1a;模拟碰撞传感器的插件。 libgazebo_ros_camera.so&#xff1a;模拟相机传感器的…

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

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

@RequestParam和@RequestBody部分使用场景总结

总结代码如下 package com.woer.receipt_callback.controller;import cn.hutool.log.StaticLog; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.web.bind.annotation.*;/*** 总结&#xff1a;* 一、Ge…

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

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

NewStarCTF2023week2-Upload again!

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

JavaScript的forEach循环和作用域

forEach循环 var age [12,3,12,3,12,12,1,3,3,123] age.forEach(function(value){console.log(value) }) for(var num in age){ if(age.hasOfProperty(num)){ console.log("存在") console.log(age[num]) } } num是下标位置&#xff0c; 通过get方法获取字符串相…

【算法与数据结构】--常见数据结构--树与图

一、二叉树 二叉树&#xff08;Binary Tree&#xff09;是一种重要的树状数据结构&#xff0c;它由节点构成&#xff0c;每个节点最多有两个子节点&#xff1a;一个左子节点和一个右子节点。这种结构使得二叉树在计算机科学和编程中具有广泛的应用。 1.1 二叉树的基本特性&am…

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

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

Springboot 集成 WebSocket

WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务端主动向客户端推送数据。在WebSocket API中&#xff0c;浏览器和服务器只需要完成一次握手&#xff0c;两者之间就直接可以创建持久性的连接…

python 批量使图片重新排序

** 导入相关库 ** import os设置图片文件夹的路径 image_folder " D:\\images"获取文件夹中的所有图片文件 image_files [f for f in os.listdir(image_folder) if f.endswith(".jpg")]确保文件夹中至少有一个图片文件 if not image_files:print(&qu…