510-C++问题总结(1)

迈不过友情╰ 2022-09-09 12:56 258阅读 0赞

1、C++this指针干什么用的?
1个类型定义的对象都有各自的成员变量,但是是共享一套成员方法,在成员方法里,是访问谁的成员变量,这个是靠this指针区分的。1个类型定义了很多对象,都是私有的成员变量,但是共享一套成员方法,在成员方法里面访问谁的成员变量?通过this指针区分。
C++的类的普通成员方法在被编译的时候都会多出来一个this指针,
在这里插入图片描述
通过this指针可以区分这个方法到底操作的是哪个对象的成员。

2、C++的new和delete,什么时候用new[]申请,可以用delete释放?
new和delete本质上是一个运算符重载。operator new,operator delete
当我们用new[]来开辟一个数组内存的时候,相应的在释放这个内存的时候得使用delete[]ptr;
delete相当于free有两件事情要做:第一个是调用析构函数,第二个是释放内存。
如果是自定义类型而且提供了析构函数,那么用new[]开辟,就一定需要用delete[]ptr释放。delete[]知道是要释放一个数组内存,就要把数组的每个对象进行析构,然后调用析构函数的时候要传入每个对象的起始地址,就要知道这个内存上有多少个对象,需要把ptr指针-4,才能取到这块内存存储了多少个对象的值。比如说,new Test[10]; 实际上除了开辟10个Test对象的内存,还需要额外开辟4字节的内存,记录开辟对象的个数。new底层调用malloc开辟内存。
其他的情况,都可以用delete释放。

3、C++的static关键字的作用(我从elf结构,链接过程来回答)?
从面向过程来说:static可以修饰全局变量,函数,局部变量。
static修饰全局变量和函数,本来是整个工程可见,现在变为仅当前文件可见,全局变量或者函数被static修饰以后,在符号表中, 符号的作用域从g(global)变成l(local)了。(局部变量是指令,本身不产生符号,通过ebp-偏移量来访问的,加上static修饰局部变量,变成数据段,要产生符号了,local)
static修饰局部变量的话,这个变量的内存位置就变到.data段(存储初始化且初始化不为0的数据)或者.bss段(存储未初始化或者初始化为0的数据)了。因为在数据段,程序一开始就开辟内存,第一次运行到它才初始化,只初始化1次。

从面向对象的角度来说,static可以修饰成员变量,也可以修饰成员方法,也可以在成员方法里定义静态的局部变量。
static修饰成员变量,这个成员变量就从对象私有变成对象所共享的。
static修饰成员方法也一样,变成对象共有的,相当于成员方法不再产生this指针,也就是说,这些方法不需要用对象来调用,用类的作用域来调用。

4、C++的继承?
继承(a kind of)是属于类和类之间的关系,类与类之间常见的关系还有 组合(a part of)。
继承有2大好处:1.代码的复用,通过1个简单的继承,就可以把基类的成员复用到派生类。2.通过继承,在基类里面给所有派生类可以保留统一的纯虚函数接口,等待派生类进行重写,通过使用多态(基类指针或者引用指向从这个基类派生的不同的派生类对象,这个基类指针或者引用指向谁,就可以访问谁的同名覆盖方法),可以通过基类指针访问不同派生类对象的重写方法(同名覆盖方法)!只要持有基类的指针,不管这个指针传进来是哪个派生类对象,都可以访问这个派生类对象的同名覆盖方法。基本上可以做到开闭原则,添加新的功能可以添加一个额外的派生类从基类继承而来,重写基类的纯虚函数接口就可以了。

5、C++的继承多态,空间配置器,vector 和list的区别,map,多重map?
继承在第4题已经阐述了。
多态:静多态(编译时期的多态),动多态(运行时期的多态)

静多态(编译时期的多态):函数重载和模板。函数重载:一个函数名展现出来很多不同的状态,因为参数列表不同,到底是调用哪个函数重载的版本,这个调用点在编译时就要确定的。模板:可以通过不同类型的实例化展现出来。用什么类型从模板实例化代码?这个从编译时确定的。
动多态(运行时期的多态):虚函数 ,指针/引用指向派生类对象
动多态的好处是可以用统一的基类指针或者引用通过指向不同的派生类对象,访问不同派生类对象的同名覆盖方法。我们在写接口时,全部都是基类的指针或者引用就可以,不放具体的派生类。

空间配置器allocator:给容器使用的,主要作用把内存开辟和对象构造分开,把对象析构和内存释放分开。原本我们使用new,new不仅开辟空间还会构造对象,delete不仅释放空间还对象析构。我们为什么把它们分开呢?当我们去初始化1个容器的时候,这些容器理应是空的,底层只有内存,不应该有对象,如果在容器构造的时候直接new,不仅仅开辟内存还会构造很多无用,我们不需要的对象。当我们从容器删除元素的时候,只是需要把对象析构掉,并不需要释放对象的内存,那个内存是容器的内存,容器以后还要使用。当容器出作用域,把有效的对象析构掉,然后释放内存,如果用delete,会把容器底层所有位置上的都当做对象析构掉。

vector和list的区别
vector是数组,底层是可以2倍扩容的数组,提供的尾部的增加和删除,push_back,pop_back,O(1)的操作。随机访问多(O(1))(优先级队列是基于vector实现的,底层是大根堆),数组在中间这些位置增加或者删除都是时间复杂度O(N)的操作

list是循环的双向链表,节点内存不是连续的,每一个节点都是new出来的,适合于增加和删除操作多的场景,首尾增加和删除的时间复杂度都是O(1)
因为其他节点不会改动。

map(不允许key重复的):映射表[key-value],底层实现是红黑树(二叉排序树),通过快速找到key,来找到key对应value。
multimap(允许key重复的)
红黑树:5个性质,插入3种情况(最多旋转2次),删除(最多旋转3次)4种情况

6、C++如何防止内存泄露?智能指针详述?
内存泄漏:分配的堆内存(没有名字,只能用指针来指向)没有释放,也再没有机会释放了,也就是指向堆内存的指针指向其他地方去了,找不着原来的内存,也没有机会释放。

  1. int *p = new int[10000];
  2. if(xxx)
  3. return;//运行抛异常了
  4. delete []p;

使用智能指针来防止内存泄漏(智能指针利用栈上对象出作用域自动析构的特点,在智能指针的析构函数就把资源释放了)

  1. unique_ptr pre(new int[100000]);
  2. //不管代码从哪里return,只要出函数栈帧,对象就要析构,在对象析构函数中释放资源

auto_ptr/scoped_ptr/unique_ptr shared_ptr/weak_ptr

7、C++如何调用C语言函数接口?
因为C和C++生成符号的方式不同,所以C和C++语言之间的API接口是无法直接调用的。怎么办?
C语言的函数声明必须扩在extern “C”{}
在这里插入图片描述
这个宏的作用是:C++编译器内置了这个宏,如果是C语言编译器来编译这个代码,没有这个宏,就直接使用C接口就可以了,如果是C++环境,因为有这个宏,extern C就会展开,告诉C++编译器这个函数sum是在C语言下生成的,调用它的话按照C语言的符号规则来去找它。按照C语言的符号规则就是sum,按照C++语言的符号规则就是sum_int_int。

8、C++什么时候会出现访问越界?
(从本质上来说,访问越界就是,系统给我们分配了既定大小的内存,我们理应在这个既定大小的内存中访问,但是由于某些原因,我们访问这个内存超过了系统给我们分配的既定内存。)

1.访问数组元素越界了
2.vector容器访问 vector< int > vec; vec[2]; 这样也访问越界,vector是空容器,什么元素都没有
3.string str; str[2] 空字符串,也是访问越界
4.array(C++11提供的内存不可扩容)访问超过范围的下标也是访问越界
5.字符串处理,没有添加’\0’字符,导致访问字符串的时候越界了
6.使用类型强转,让一个大类型(派生类)的指针指向一块小内存(基类对象)了,然后指针解引用,访问的内存就越界了!

9、C++中类的初始化列表?
可以指定对象成员变量的初始化方式,尤其是指定成员对象的构造方式;

成员变量的初始化方式,初始化顺序是和定义的先后顺序有关,和在初始化列表出现的顺序是没有关系的。

10、C和C++的区别?C和C++的内存分布有什么区别?
C++支持:
1.引用(是一种更安全的指针)
2.函数重载
3.new/delete 和C的malloc/free有区别
4.const, inline,带默认值参数的函数
5.模板,泛型编程
6.类和对象 OOP =》采用设计模式
7.STL标准库
8.有异常 智能指针 运算符重载(让对象的运算和内置类型一样)

C和C++的内存分布实际上没什么区别。
user space reserve(从0开始,不能读也不能写) .text .rodata (只能读不能写) .data .bss heap stack 命令行参数和环境变量
kernal space ZONE_DMA ZONE_NORMAL(.text .rodata .data. bss. heap stack) ZONE_HIGHMEM

11、int* const p和const int p区别?
int \
const p 这个const修饰的是指针p,这个p不能修改,但是p可以修改
const int \
p 这个const修饰的是 * p,*p不能修改,但是p可以修改。

12、malloc和new区别?
1.malloc按字节开辟内存 ,new底层也是通过malloc开辟内存,但是new还可以提供初始化。
2.malloc开辟内存失败返回的是nullptr,而 new开辟失败,抛出bad_alloc类型的异常
3.malloc 是调用C的库函数 new是operator new,是运算符的重载函数
4.malloc 不管是开辟单个的内存还是数组的内存,方式都是一样的。
而new开辟单个的是 new int(10); 开辟内存数组的是new int[20] (); 没有new int[20] (40)这样的功能

13、map&set容器的实现原理?
set称作集合,只存储key;
map映射表,存储[key,value]键值对,
它们的底层数据结构都是红黑树,都是通过key进行元素比较

14、shared_ptr引用计数存在哪里?
在这里插入图片描述
堆上分配的

15、STL、map底层、deque底层、vector里的empty()和size()的区别、函数对象?
STL标准容器 =》 顺序容器(vector,deque,list),容器适配器(stack,queue,priority_queue),关联容器(有序(set和map)和无序(底层是链式哈希表))
还有近容器 数组,string,bitset 迭代器 泛型算法
map底层是红黑树
deque底层是动态开辟的二维数组
deque的实现有这2个宏 ,一维默认size是2
在这里插入图片描述
比如说用整型实例化deque,二维大小就是1024
deque底层内存不是连续的,正在开辟的二维数组
在这里插入图片描述
vector里的empty()和size()
在这里插入图片描述

在这里插入图片描述
用last-first,firs指向的是vector底层内存的起始地址,last指向的是最后一个有效元素的后继位置,end指向的是内存的末尾地址,

函数对象(拥有()运算符重载函数) 使用在泛型算法当中
operator() test(); test.operator()(); sort find_if priority_queue set map

发表评论

表情:
评论列表 (有 0 条评论,258人围观)

还没有评论,来说两句吧...

相关阅读

    相关 1. c#学习总结

    C\学习总结 > c\是一门高级开发语言,通过微软自身的.net作为支撑,可以跨平台使用,c\开发的重点还是对.net的使用,,.net就相当于jdk,不过比jdk更高级

    相关 c/c++】笔试题总结1

    总结1 1. 多态类中的虚函数表是Compile-Time,还是Run-Time时建立的? 答:虚拟函数表是在编译期就建立了,各个虚拟函数这时被组织成了一个虚拟函数的入

    相关 510-C++问题总结(1)

    1、C++this指针干什么用的? 1个类型定义的对象都有各自的成员变量,但是是共享一套成员方法,在成员方法里,是访问谁的成员变量,这个是靠this指针区分的。1个类型定义

    相关 CodeForces 510C Fox And Names

    一道拓扑排序题!! 注意判断各种情况,两个字符串比较的时候,从左向右开始比较,当出现不同的字母后,不再向后比较。一个是另一个的前缀,那么长的在后面。 当给出的顺序出现环的时

    相关 C语言总结1

    1、简述TCP和UDP的区别 TCP是传输控制协议,提供的是面向连接的、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。