C++面向对象的常见面试题目(二)

1. 继承关系下,析构函数和构造函数执行顺序?

构造函数按照依赖链,从强到弱构造

首先调用基类的构造函数。如果有多个基类,则按照它们在派生类声明中出现的顺序调用;接下来,按照它们在类中声明的顺序,调用派生类中所有非静态成员变量(包括从基类继承的成员变量)的构造函数;最后调用派生类自己的构造函数体。这意味着,派生类的构造函数有机会使用已经初始化完毕的基类成员和派生类成员。

析构函数按照依赖链,从弱往强进行析构

首先执行派生类的析构函数体;然后按照它们在类中声明的逆序,调用派生类中所有非静态成员变量的析构函数;最后调用基类的析构函数;如果有多个基类,同样按照它们在派生类声明中逆序调用。

2. 虚函数表和虚函数表指针的创建时机

编译器发现类中包含 virtual 关键字修饰的函数就会创建虚函数表。虚函数表的内容在编译的时候就已经生成了。虚函数表存储在全局数据区的只读数据字段中,虚函数表是存放虚函数的地址的数组。

当一个包含虚函数的类的对象被创建时,编译器会确保在对象的内存布局中包含一个指向虚函数表的指针,即vptr。vptr的初始化(即赋值为虚函数表的地址)通常发生在对象构造函数执行的过程中。即使没有显示定义构造函数,编译器也会自动生成一个默认构造函数来完成这项任务。

在继承关系中,调用基类构造函数的时候,先将基类的虚函数表地址赋值给 vptr,接着调用子类构造函数的时候,又将子类的虚函数表地址赋值给 vptr。

3. 虚析构函数的作用

虚析构函数是在C++中,为了实现多态性而在基类中声明为虚函数的析构函数。

在继承下,为了使子类析构函数能得到正常调用,需要将基类的析构函数设置为虚析构函数。

设置虚析构函数是有代价的,编译器会为类生成虚函数表,每个对象都需要持有 vptr

4. 手动管理指针可能出现哪些问题?

野指针:指向了一个未知的、无效的或者未初始化的地址

指针悬挂:释放了内存但是忘记把指针置空

踩内存:程序在运行过程中发生了越界

没有释放资源产生内存泄漏,重复释放资源引发coredump

5. C++智能指针的原理

unique_ptr: 代表独占所有权的智能指针。它保证同一时间内只有一个unique_ptr实例拥有指向对象的指针。当unique_ptr离开作用域时,它会自动删除所拥有的对象,从而释放内存

shared_ptr: 引用计数,允许多个智能指针共享同一个对象的所有权。它通过引用计数机制工作,即一个控制块(通常是一个原子计数器)记录有多少个shared_ptr指向同一块内存。当最后一个指向该内存的shared_ptr销毁时,引用计数减至零,此时控制块会自动释放这块内存。

weak_ptr: 一种不增加引用计数的智能指针,它用于非拥有地观察由一个或多个shared_ptr管理的对象。主要用于解决循环引用的问题,因为weak_ptr不会增加被观察对象的引用计数,即使持有weak_ptr的实例很多,也不会阻止对象被销毁。

6. 静态库和动态库的区别

(1)链接方式:静态链接把静态库编译到目标文件;动态链接没有把库编译到目标文件,而是在程序运行时才去加载代码

(2)空间占用:静态库会存在多个副本,动态库只有一个副本

(3)使用方式:静态库 程序直接运行,动态库需要根据指定的路径查找动态库

(4)执行速度:动态库执行慢,静态库执行速度较快

(5)库文件发生变更:接口变更都需要重新编译,接口实现改变如果是动态链接只需要重新编译动态库。

7. 使用过C++11哪些新特性

新的语法糖:auto, decltype, nullptr, final, override, const, 基于范围的for循环,function函数对象

 STL容器:vector、list、unordered_ma、unordered_set

智能指针:shared_ptr, weak_ptr, unique_ptr

多线程:thread、mutex、lock_guard、condition_variable、atomic

右值引用:T &&;实现移动语义和完美转发

8. 左值引用和右值引用的区别?右值引用的意义?

左值可以在等号左边,能够取地址,有一个具体的名字,右值只能在等号右边,不能取地址,不具名。

左值常见例子:变量名,返回左值引用的函数调用,前置自增自减,解引用表达式

右值常见例子:字面值,返回非引用类型的函数调用,后置自增自减,算数表达式,逻辑表达式,比较表达式,将亡值

右值引用的意义:避免资源的复制,实现资源所有权的转移,在模板编程中,右值引用和模板参数的结合使用可以实现完美转发(perfect forwarding),允许将函数参数以原始类型(左值或右值)转发给其他函数。

10. 什么是将亡值?

指的是即将被销毁的对象。这个概念是在C++11标准中引入的,用于描述那些即将被移动(move)操作所消费的对象。移动操作是一种优化技术,它允许将资源(如内存、文件句柄等)从一个对象转移到另一个对象,而无需复制这些资源。

这是一条吃饭博客,由挨踢零声赞助。学C/C++就找挨踢零声,加入挨踢零声,面试不挨踢!

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值