c++常见面试题

c++常见面试题

  • c++ this 指针干什么用的?

一个类型定义了很多对象,对象之间拥有各自的成员变量,共享一套成员方法。this指针用来区分是那个对象的成员变量和那个对象调用了成员方法( 成员方法的第一个参数由编译器默认加上该对象的地址值(this指针) )

  • c++的new和delete,什么时候用new[] 申请,可以用delete释放

如果是自定义类型且提供了析构函数,会在对象数组前占用8字节用于记录对象的个数(强调:一定要有析构函数),那么使用new[]时一定要使用delete[],当未提供析构函数时,类型为自定义类型,使用new[]开辟内存可以使用delete释放

1
2
3
4
5
6
7
8
9
class A {
public:
A() { printf("A() %#x \n",this); }
//~A() {}
int a = 0;
int b = 0;
double c = 0;
};
执行:A * pa = new A[10];

当不存在析构函数时,pa所指内存及前8字节

1
fd fd fd fd   00 00 00 00   00 00 00 00   00 00 00 00   00 00 00 00 后全为0

当存在析构函数时,pa所指内存及前8字节

1
0a 00 00 00   00 00 00 00   00 00 00 00   00 00 00 00   00 00 00 00  后全为0
  • c++ static关键字作用

static修饰全局变量,函数时将其作用域变为当前文件可见,在符号表中符号的作用域就从 global 变为 local

static修饰局部变量(一般为函数内的静态变量)在第一次使用时分配内存并初始化。这里的变量包含内置数据类型和自定义类型的对象,位于 .bss段 或 .data段,符号作用域为 local

static修饰类成员变量,是的该变量为类中公有可以通过类直接访问。修饰类成员方法,可以直接通过类访问而不需要对象

  • c++如何防止内存泄漏

内存泄漏是指分配的内存没有释放,也没有机会释放,如忘记,或在释放之前抛异常。解决方式是使用智能指针

  • STL中迭代器失效问题

迭代器不允许一边读一边写。当通过迭代器插入一个元素,所有迭代器失效。当通过迭代器删除一个元素时,当前删除位置到后面所有元素的迭代器就都失效了。

当通过迭代器更新容器元素以后,要及时对迭代器进行更新,insert / erase 方法都会返回新位置的迭代器

  • 构造函数和析构函数能不能是虚函数

构造函数不能是虚函数,对象在构造函数之后产生,没有对象就没有 vfptr

析构函数可以,当基类中拥有虚函数时,必须其析构函数必须为析构函数

  • 宏和内联函数的区别

#define 的处理时机是在预处理 inline 的处理时机是在编译阶段 , inline在函数调用点展开,通过函数的实参把函数代码直接展开调用,节省了函数调用栈的开销,但inline只是一种建议

  • 拷贝构造为什么传引用不传值

若存在拷贝构造为 :A &operator=(const A other) 当此函数被调用时,先发生拷贝构造,用于构造 A other,然后调用operator=。若使用引用,则避免了拷贝构造带来的开销

  • 如何实现一个不可以被继承的类

派生类的构造过程为:基类构造->派生类构造,故只需可将基类构造函数私有化

c++11 中引入final 用于阻止类的继承和虚函数的重写

  • 什么时纯虚函数,为什么要有纯虚函数,虚函数表放在那里

virtual void func() = 0; func就为纯虚函数,拥有纯虚函数的类称为抽象类(不能定义对象,但可以定义指针或引用)

纯虚函数一般定义在基类中,基类不代表任意实体,它主要的作用之一是给所有的派生类保留统一的接口,方便使用多态,基类也不需要实例化

虚函数表位于 .rodata 段

  • c++中的const 以及和 static 的区别

const修饰类型具有只读属性。const 定义的被称为常量,当用真正的常量初始化时在编译过程中,把出现名字相同的值进行替换,当用变量初始化时不会发生变化

const还可以修饰成员方法,其 this 指针所指对象将具有const属性,这样普通对象和常对象就都可以调用了,但是无法修改器成员变量

  • deque的底层原理

底层是一个动态开辟的二维数组,存在两个宏定义:#define MAP_SIZE 2 #define QUE_SIZE(T) 4096/sizeof(T) ,其中MAP_SIZE是一维数组的个数,QUE_SIZE 是二维数组的大小

  • 异常机制是怎么回事

try {可能抛出异常的代码} catch(类型){捕获相应异常类型对象,进行处理,完成后代码继续运行},处理过程是栈展开,首先查看当前函数栈中是否存在对应的catch若有则处理,没有则销毁当前函数栈,向调用方抛出异常

  • 早绑定和晚绑定

早绑定:普通函数的绑定,对象调用虚函数

晚绑定:用指针或引用调用虚函数

  • 智能指针交叉引用问题怎么解决

在定义对象时使用强智能指针 share_ptr 引用对象时使用弱智能指针 weak_ptr