1.c++与c的区别
- c++是面向对象的语言,c是面向过程的语言。
- c++与c的动态管理内存的方法不一样,c++是new/delete,c是malloc/free
- c++有引用,c没有。
- c++具有封装,继承,多态的特性。
2.如何让一个c++程序执行c的程序且不需要对函数进行名字重整
extern "C";
3.指针与引用的区别
- 指针是一个实体需要分配内存空间,引用只是变量别名不需要分配空间。
- 指针在定义是不一定需要初始化而且可更改,引用必须进行初始化且不能更改。
- 引用的低层就是通过指针实现的。指针有多级指针。
- 在进行参数传递时,指针传的时指针的地址,引用传的是变量的地址。
4.c++中间的指针传递和引用传递
- 指针传递本质就是值传递,它所传递的是一个地址值,他会开一个新的空间作为被调函数的局部变量,看作一个副本,且不影响主题。
- 引用传递在栈上开辟空间放放的是它所传递的是一个地址值,任何操作都是间接操作本体,会修改本体的值。
5.形参与实参
- 形参变量只有在被调用时才分配内存单元,在调用结束时, 即刻释放所分配的内存单元,只能在函数内部有用。
- 实参可以是常量、变量、表达式、函数等,它们都必须具有确定的值。
- 实参和形参在数量上,类型上,顺序上应严格一致。
6.三种传递
- 值传递:有一个形参向函数所属的栈拷贝数据的过程,耗费空间时间 (传值)
- 指针传递:形参向函数所属的栈拷贝数据的过程,但拷贝的数据是一个固定为4字节的地址。(传值,传递的是地址值)。
- 引用传递:为该数据所在的地址起了一个别名(传地址)
- 指针传递和引用传递比值传递效率高。一般主张使用引用传递。
7.static
- 隐藏,默认初始化为0。
- 保持变量永久化,在程序刚开始运行时就完成初始化。
- 在类中的static成员变量属于整个类所拥有,在类中的static成员函数属于整个类所拥有不接收this且只能访问静态成员。
- static修饰的变量要在类外初始化,且不接受virtual修饰。
8.静态变量的初始化
- 初始化只有一次,但可以多次赋值,在主程序之前编译器已经分配好内存。
9.const
- 阻止一个变量的改变,const类型变量必须定义的时候进行初始化
- const可以修饰形参,在函数内部不能改变其值
- 对于类的成员函数用const 类的常对象只能访问类的常成员函数
- const成员函数可以访问非const对象的非const数据成员、const数据成员,也可以访问const对象内的所有数据成员
- 非const成员函数可以访问非const对象的非const数据成员、const数据成员,但不可以访问const对象的任意数据成员
- const_cast将const类型转换为非const类型
10.指针与const
- int const p2 这里的const修饰p2的值,p2只能指向固定的一个变量地。可通过p3读写这个量
- int const p1 这里修饰修饰p1了,不可以给*p1赋值改变p1指向变量的值,
11. mutable
- 如果需要在const成员方法中修改一个成员变量的值,mutable修饰的成员变量不受const成员方法的限制。
12.extern
- a.c需要引用b.c中变量int v或函数,需要在a.c中声明extern int v。
13.int转字符串以及字符串转int
- int->string to_string()这个库函数。。
- string->int istringstream 用字符串流来实现,
istringstream is("12"); //构造输入字符串流,流的内容初始化为“12”的字符串 int i; is >> i;
14.深复制与浅复制
- 浅复制,就是一个指针指向了要被复制的内存地址,如果原改变,复制出来的也改变。
- 深复制, 就是开辟一个新空间直接存放。
15.c++模板以及底层
- 编译器从函数模板通过具体类型产生不同的函数;编译器会对函数模板进行两次编译:在声明的地方对模板代码本身进行编译,在调用的地方对参数替换后的代码进行编译。
16.c的struct与c++的struct
- c语言中struct是用户自定义数据类型。c++中的是抽象数据类型,支持函数成员定义。
- c中的是没有权限定义的,c++中的权限定义为public,而class的为private。c++中struct与class大体相同就是权限不同。
17.虚函数与纯虚函数
- 虚函数和纯虚函数可以定义在同一个类,含有纯虚函数的类被称为抽象类,而只含有虚函数的类不能被称为抽象类。
- 虚函数可以被直接调用,纯虚函数必须被之类的函数实现后才可以被调用。
- 虚函数必须实现,纯虚函数不需要实现
- 虚函数主要防止内存泄漏。
virtual void Demon() = 0; //纯虚函数
virtual void Base() { cout << "this is farther class" << endl; } //虚函数
18.虚函数和inline
- 虚函数用于实现多态,而内联函数用于提高效率
- 内联函数在编译期间代码替换成函数代码
- 虚函数要求在运行时进行类型确定,而内敛函数要求在编译期完成相关的函数替换,虚函数不可被声明为inline。
19. 类成员初始化方式?构造函数的执行顺序 ?为什么用成员初始化列表会快一些?
- 赋值初始化,通过在函数体内进行赋值初始化,是在所有的数据成员被分配内存空间后才进行的。
- 列表初始化,在冒号后使用初始化列表进行初始化,是给数据成员分配内存空间时就进行初始化。
- 由于赋值需要消耗时间与空间所以,成员初始化更快。
- ① 虚拟基类的构造函数,② 基类的构造函数,③ 类类型的成员,④ 派生类自己的构造函数。
20. 构造函数为什么不能为虚函数?析构函数为什么要虚函数?
- 虚函数是实质上是储存在对象的内存空间里的,在调用构造函数时,对象还没实体化,
- 虚函数的存在主要是防止内存泄漏,所以析构函数需要用虚函数。
21. 析构函数的作用,如何起作用
- 用于撤销对象的一些特殊任务处理,可以是释放对象分配的内存空间,无参数,无返回值,不重载,且只有一个。
22.析构与构造是否可以为虚函数
- 虚函数是实质上是储存在对象的内存空间里的,在调用构造函数时,对象还没实体化,不安全。
- 析构函数在调用时已经删除空间了,还是不安全。
23.构造函数与析构函数调用顺序。
- ① 基类构造函数,② 成员类对象构造函数,③ 派生类构造函数。
- 派生类的析构函数,成员类对象的析构函数,基类的析构函数。
24.类的两种建立方式,以及单独使用一种构造方式
- 静态建立,就是由编译器为对象在栈空间中分配内存。
- 动态建立一个类对象,就是使用new运算符为对象在堆空间中分配内存
- 单独使用静态建立new、delete运算符重载为private属性,单独使用动态建立构造、析构函数设为protected属性
25.什么情况会自动生成默认构造涵树
- 个类没有任何构造函数,但它含有一个成员对象,而后者有默认构造函数
- 其基类有默认构造函数。
- 有虚函数的类
26.类的继承
- 一个类继承了另一个类的属性和方法。
- 子类拥有父类的所有属性和方法,子类可以拥有父类没有的属性和方法,子类对象可以当做父类对象使用
- public、protected、private
27.组合
- 一个类里面的数据成员是另一个类的对象
- 先调用内嵌对象的构造函数,然后按照内嵌对象成员在组合类中的定义顺序,执行组合类构造函数的函数体。
28. 抽象基类为什么不能创建对象
- 里面带有纯虚函数的类叫做抽象类,抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。
- 将有关的操作作为结果接口组织在一个继承层次结构中。
- 抽象类是不能定义对象的。一个纯虚函数不需要(但是可以)被定义
29. 类什么时候会析构
- 对象生命周期结束,被销毁时。
- delete指向对象的指针时。
- 对象i是对象o的成员,o的析构函数被调用时,对象i的析构函数也被调用。
30.友元函数
- 友元函数必须在类内部声明。
- 编译器必须能够读取这个结构的声明以理解这个数据类型的大、行为等方面的所有规则。
31.C++里面的多态
- 静态多态:重载和模板,在编译的时候确定。
- 动态多态:覆盖和虚函数实现,在运行是确定。
32.继承机制
- 将派生类指针或引用转换为基类的指针或引用被称为向上类型转换,向上类型转换会自动进行,而且向上类型转换是安全的。
- 将基类指针或引用转换为派生类指针或引用被称为向下类型转换,用dynamic_cast进行向下类型转换。
33.组合和继承
- 继承的优点是子类可以重写父类的方法来方便地实现对父类的扩展,缺点:子类可见父类的各种细节,如果父类进行修改,子类也需要修改。
- 所包含的对象的内部细节对当前对象时不可见,一个低耦合关系,缺点:容易产生过多的对象。
34.左值和右值
- 可以进行取地址有名字的就是左值,反之就是右值。
- 右值值引用通常不能绑定到任何的左值
- 右值又分为纯右值和将亡值,纯右值等同于 临时变量和不跟对象关联的字面量值,将亡值可以理解为通过“盗取”其他变量内存空间的方式获取到的值。
- 右值值引用通常不能绑定到任何的左值,通常需要std::move()将左值强制转换为右值。
a = b+c; // a为左值,b+c为右值,函数的返回值也是右值。
35.移动构造函数和拷贝函数
- 拷贝构造函数就是把开辟一块新的地址把旧的拷贝过去。
- 移动构造函数就是两个指针指向同一片内存空间。
- 拷贝构造函数的参数是一个左值引用,但是移动构造函数的初值是一个右值引用。
36. C语言的编译链接过程
- 源代码-->预处理-->编译-->优化-->汇编-->链接–>可执行文件
37.vector和list
- vector和数组类似,拥有一段连续的内存空间,当数组中内存空间不够时,会重新申请一块内存空间并进行内存拷贝。
- list是由双向链表实现的,因此内存空间是不连续的,高效的插入和删除。
list如果取第几个的话就是强行遍历
int size= a.size();
vec.at(size-n); //这就是倒数第几个
38.STL vector
- size()函数返回的是已用空间大小,capacity()返回的是总空间大小,capacity()-size()则是剩余的可用空间大小。
- 如果超出vector的大小的话,vector的空间会自动申请一个原来的2倍大的空间。可以保证常数的时间复杂度。
- vector所占用的空间只增大不减小。
39.STL迭代器
- 迭代器是一种抽象的设计理念,通过迭代器可以在不了解容器内部原理的情况下遍历容器,也是容器与STL算法的粘合剂。
- 迭代器的作用就是提供一个遍历容器内部所有元素的接口。
- 最常用的迭代器的相应型别有五种:value type、difference type、pointer、reference、iterator catagoly。
40.set与hash_set
- set的底层为红黑树,而且有自动排序的功能。
- hash_set的底层是哈希表,不具有排序功能呢,而且一些类型无法处理。
41.hashmap与map
- map底层为红黑树,map有自动排序功能,
- hashmap为哈希表,没有自动排序,而且一些类型无法处理。
42.map和set
- 底层都用红黑树来实现的,插入和删除都在log级别。
- 有模板定义如果是key+value就是map,如果是value就是set
- 因为红黑树可以实现自动排序。时间复杂度比较低。
43.unordered_map(hash_map)和map的区别,hash_map如何解决冲突以及扩容
- .unordered_map底层是由哈希表,而且元素无序,哈希表用的是开链法解决冲突的。
- map底层为红黑树,元素有序。
- 当向容器添加元素的时候,如果大于等于阈值—即当前数组的长度乘以加载因子的值的时候,就要自动扩容。
44.vector越界访问下标,map越界访问下标?vector删除元素时会不会释放空间
- 通过下标访问vector中的元素时不会做边界检查,即便下标越界,返回的是这个地址中的值。
- 将key作为下标去执行查找,并返回相应的值;如果不存在这个key,就将一个具有该key和value的某人值插入这个map。
- erase()函数,只能删除内容,不能改变容量大小。
45.map[]与find()
- map[]是以关键字去查找,并返回对应的值,如果没有就插入这个关键字的默认进map。
- find是根据关键字查找,找到就返回该位置的迭代器,如果没有就返回尾迭代器。
46.list与deque
- list是环状双向链表,只需要一个指针。
- deque是一种双向的练习线性空间,在头尾都可以进行插入和删除操作,deque没有所谓的空间保留功能。
47.函数指针
- 函数指针指向的是特殊的数据类型,函数的类型是由其返回的数据类型和其参数列表共同决定的,而函数的名称则不是其类型的一部分。
int (*pf)(const int&, const int&)
上面的pf就是一个函数指针,指向所有返回类型为int,并带有两个const int&参数的函数。注意*pf两边的括号是必须的。
- 我们希望在同一个函数中通过使用相同的形参在不同的时间使用产生不同的效果于是就有了函数指针。
48.c++的内存分配,以及内存区
- 栈区:由系统进行分配,主要放函数的参数值,局部变量等
- 堆区:般由程序员进行分配,分配方式倒是类似于链表。
- 静态区:程序结束后由系统释放。
- 文字常量区:常量字符串就是放在这里的。程序结束后由系统释放。
- 程序代码区:存放函数体的二进制代码。
49.堆和栈的区别
- 栈是由编译器管理的,堆是由程序员控制的。
- 堆可以达到4G的空间在32位系统下。默认栈的大小为1M。
- 堆的生长方向是向上增长的向着内存地址增加的方向,而栈是向着内存地址减小的方向增长。
- 堆的效率比栈要低得多
50.野指针
- 指向内存被释放的内存或者没有访问权限的内存的指针
- 指针变量未初始化。
- 指针被delete后未置nullptr
- 指针超过了变量范围。
51.野指针和空悬指针。
- 野指针指,访问一个已删除或访问受限的内存区域的指针,野指针不能判断是否为NULL来避免。指针没有初始化,释放后没有置空,越界。
- 一个指针的指向对象已被删除,那么就成了悬空指针。野指针是那些未初始化的指针。