嵌入式八股 - C++ 一

1、C++中如果一个类被继承,那么它的析构函数会怎么处理?

在继承中,对象的析构顺序与构造顺序是相反的,遵循先构造的后析构的原则。先调用派生类的析构函数,而后调用基类的析构函数。

2、引用和指针区别

1)引用

  • 引用本身是变量的别名,不占用额外内存空间
  • 引用必须在声明时进行初始化(不能为空)
  • 引用一旦初始化不能再改变其指向
  • 引用可以像普通变量一样直接使用,无需解引用
  • 引用不能进行自增自减操作
  • 使用sizeof时返回它所引用的对象本身的大小

注意:使用引用时往往是避免额外的拷贝开销!

2)指针

  • 指针是指向变量地址,本身占用额外内存空间
  • 指针在声明时可以不初始化,但是强烈建议初始化(不然野指针)
  • 指针可以在初始化后修改指针指向
  • 指针需要使用*进行解引用以访问对象
  • 指针可以进行自增自减操作
  • 使用sizeof时返回指针本身的大小

3、左值与右值

左值指有明确内存地址的对象,而右值指临时的没有明确内存地址的对象。

其区分的关键在于对象有无分配内存地址,可否使用&取地址。

4、左值引用和右值引用

1)左值引用

在 C++ 中,左值引用 是一种引用类型,它绑定到一个左值。左值引用使用 & 符号声明,主要用于别名或避免对象拷贝。

  1. 普通左值引用 (T&):只能绑定到非 const 的左值。它不能绑定到字面量、临时对象等右值。
  2. 常左值引用 (const T&):万能引用,既可以绑定左值,也可以绑定右值。绑定右值时,会延长该临时对象的生命周期。

关键特性:

  • 必须初始化
  • 不能绑定到临时对象(右值)
  • 引用一旦绑定,不能更改指向的对象

2)右值引用

右值引用 (T&&)就是对一个右值进行引用的类型,其只能绑定到右值,包括字面量、临时对象,以及通过 std::move() 转换后的左值,可以延长绑定对象的生命周期。一个右值引用变量本身是一个**左值,**可以被取地址。

需要注意的是右值引用主要有两种主要使用特性:

  • 实现移动语义

在处理有大量动态内存的类时,实现资源转移。也就是说不需要大量资源的拷贝,只是转移资源使用。

  • 引用折叠

对于使用auto &&以及模版参数为T &&时,其引用类型取决于初始化的值类型。右值推导的auto &&以及T &&为右值引用,非右值推导的auto &&以及T &&皆为左值引用。

注意:

无论声明左值引用还是右值引用都必须立即进行初始化

5、C++中的const关键字

C++中const 的用法非常灵活,其可以应用于变量、指针、函数参数、成员函数、引用和返回值。相对于C中,其主要多了有关成员函数、成员变量、引用以及对象的用法。其主要用法如下:

  • 修饰变量为常量,不能被修改
/************  修饰普通变量 ************/
const int sum = 100; // 定义一个整型常量,不能被修改
// 或者写为
int const sum = 100;
  • 修饰对象通过const 修饰的对象为常对象
/************ 修饰对象 ************/
class Stu:
const Stu stu: // 定义一个常对象
Stu const stu:
  • 修饰指针或引用
/************* 修饰指针 *************/
const int*p // 表示常量指针,其指针指向内容不可以改变,但是指针可以改变指向
int*const p //表示指针常量,其指针指向内容可以改变,但是指针不可以改变指向
const int* const p; // 指向常量的常量指针,指针不可变,值也不可变。

/************* 引用 *************/
const int& p = a;  // 表示常引用
// 或者写作
int const& p = a; 
// 注意:常引用一旦被初始化不能被修改。
  • 修饰函数参数

const修饰函数参数可以防止参数被函数改变,分为修饰普通参数、指针、引用。

  • 修饰普通参数就是修饰按值传递的参数,但是这种情况往往没有意义;
  • 修饰变量为指针时可以保护原有值仅读不会被改变,往往作为出入参数;
  • 修饰变量为引用时可以保护原有值仅读不会被改变。使用常引用修饰对象可以避免拷贝与防止修改。
  • 修饰成员函数

在类的成员函数声明末尾加上 const,称为常成员函数,其可以访问类中所有的成员变量,但是不能修改它们的值。

class Student {
public:
    // getAge 函数不修改对象状态,应声明为 const
    int getAge() const { 
        return age; 
    }
    
    // setAge 函数会修改对象状态,不能是 const
    void setAge(int a) { 
        age = a; 
    }

private:
    int age;
};

Student s;
s.setAge(20);
s.getAge(); 
  • 修饰成员变量

使用const修饰成员变量时,其值只能通过构造函数初始化列表初始化。

  • 修饰函数返回值

const修饰函数返回值是也分为修饰普通、指针、引用。

  • 修饰普通返回值时没有意义,因为普通返回值只是临时变量,其在函数返回后生命周期结束;
  • 修饰指针类型返回值时可以保护返回值不会被修改,需要注意的是这个返回值只能赋值给被 const修饰的指针;
  • 修饰引用类型返回值时可以保护返回值不会被修改。使用常引用修饰对象可以避免拷贝与防止修改。

6、C++中的static关键字

C++中 static 相对于C中,主要增加了对成员函数与成员变量的定义(C中用法看C语言文章)。

1)静态成员函数

静态成员函数也属于类本身,不依赖于任何对象实例,其可以通过 类名::函数名() 直接调用,无需创建对象。

由于静态成员函数不依赖任何对象,所以静态成员函数没有 this 指针,其不能访问类的非静态成员变量或非静态成员函数,而只能访问其他静态成员。值得注意的是静态成员函数不能定义成虚函数(后边会有这部分内容)。

class Calculator {
public:
    static int add(int a, int b) {
        return a + b; // 只能操作传入的参数或其他静态成员
    }
};

int result = Calculator::add(3, 4); // 无需创建 Calculator 对象即可调用


2)静态成员变量

静态成员变量属于类本身,而不是类的某个具体对象,也就是说类对象共享一份静态成员变量。静态成员变量在类内进行声明,必须在类外部进行定义和初始化(C++17 之前)。

class Stu{
public:
    static int count; // 声明
};

// 在类外定义并初始化
int Stu::count = 0; 

Stu a, b;
Stu::count = 5; // 通过类名访问
// a.count 也等于 5,b.count 也等于 5

7、函数传参用引用的作用是什么?以及常引用作用

1)函数传参用引用的作用

  • 避免不必要的拷贝

当参数是大型对象时,按值传递会触发拷贝构造函数,复制整个对象,这可能带来巨大的性能开销。使用引用传递,函数接收的只是原对象的一个别名,完全避免了拷贝过程。

  • 允许修改变量值

引用传递允许函数直接操作传入的实参。在函数内部对引用的任何修改,都会直接反映到原始变量上

2)常引用作用

在避免大对象拷贝、降低性能开销的同时防止对对象原始内容的修改。

8、C和C++中的struct

  • 在 C和C++中,struct 是一个由用户自定义的数据集合,只是在 C++ 中,其更类似于类功能;
  • C中struct内只包括数据成员,而C++ 中struct 可以包含成员函数、构造函数、析构函数等;
  • C中struct没有访问权限的概念,而C++内也有访问权限的区别,支持  publicprivate  和  protected  关键字;
  • C中struct定义变量时必须写上 struct 关键字,而C++中编译器会自动把结构体名当作类型名,直接声明即可。
  • C中struct不支持继承,而C++支持继承和多态。

9、C++ 中 struct和Class区别是什么?

  • 默认访问权限不同: struct 的默认访问权限是 public,而 class 的默认权限是 private
  • 默认继承方式不同:struct 继承时默认是 public 继承,而 class 的继承时默认是 private 继承。

10、什么是深拷贝、什么是浅拷贝

  • 浅拷贝是指只复制其值,不分配新内存空间;
  • 深拷贝是指分配新内存空间并且复制其值。
#嵌入式面经##嵌入式笔面经分享##嵌入式##我的求职进度条#
嵌入式面试八股汇总 文章被收录于专栏

涉及嵌入式全方面知识。根据个人学习以及面试所得,并且加上自己见解、理解记忆方法。

全部评论

相关推荐

04-17 21:25
门头沟学院 C++
点赞 评论 收藏
分享
上周组里招人,我面了六个候选人,回来跟同事吃饭的时候聊起一个让我挺感慨的现象。前三个候选人,算法题写得都不错。第一道二分查找,五分钟之内给出解法,边界条件也处理得干净。第二道动态规划,状态转移方程写对了,空间复杂度也优化了一版。我翻他们的简历,力扣刷题量都在300以上。后三个呢,就有点参差不齐了。有的边界条件没处理好,有的直接说这道题没刷过能不能换个思路讲讲。其中有一个女生,我印象特别深——她拿到题之后没有马上写,而是先问我:“面试官,我能先跟你确认一下我对题目的理解吗?”然后她把自己的思路讲了一遍,虽然最后代码写得不是最优解,但整个沟通过程非常顺畅。这个女生的代码不是最优的,但当我问她“如果这里是线上环境,你会怎么设计’的时候,她给我讲了一套完整的方案——异常怎么处理、日志怎么打、怎么平滑发布。她对这是之前在实习的时候踩过的坑。”我在想LeetCode到底在筛选什么?我自己的经历可能有点代表性。我当年校招的时候,也是刷了三百多道题才敢去面试。那时候大家都刷,你不刷就过不了笔试关。后来工作了,前三年基本没再打开过力扣。真正干活的时候,没人让你写反转链表,也没人让你手撕红黑树。更多的是:这个接口为什么慢了、那个服务为什么OOM了、线上数据对不上了得排查一下。所以后来我当面试官,慢慢调整了自己的评判标准。算法题我还会出,但目的变了。我出算法题,不是想看你能不能背出最优解。而是想看你拿到一个陌生问题的时候,是怎么思考的。你会先理清题意吗?你会主动问边界条件吗?你想不出来的时候会怎么办?你写出来的代码,变量命名乱不乱、结构清不清楚?这些才是工作中真正用得到的能力。LeetCode是一个工具,不是目的。它帮你熟悉数据结构和常见算法思路,这没问题。但如果你刷了三百道题,却说不清楚自己的项目解决了什么问题、遇到了什么困难、你是怎么解决的,那这三百道题可能真的白刷了。所以还要不要刷LeetCode?要刷,但别只刷题。刷题的时候,多问自己几个为什么:为什么用这个数据结构?为什么这个解法比那个好?如果换个条件,解法还成立吗?把刷题当成锻炼思维的方式,而不是背答案的任务。毕竟面试官想看到的,从来不是一台背题机器,而是一个能解决问题的人。
国企上岸了的向宇同桌...:最害怕答非所问了,但是频繁反问确定意思又害怕面试官觉得我笨
AI时代还有必要刷lee...
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务