面试真题 | 小米智能座舱
自我介绍
介绍项目
static关键字,在类里面使用呢?
问题回答:static关键字在类里面的使用
在C++中,static
关键字在类里面有多种用途,主要包括静态成员变量和静态成员函数。以下是详细解释:
静态成员变量
-
定义与声明:
- 静态成员变量在类内声明,但在类外定义和初始化。它不属于类的任何对象,而是属于类本身。
- 声明时使用
static
关键字,如static int count;
。 - 定义时在类外,如
int ClassName::count = 0;
。
-
存储位置:
- 静态成员变量存储在全局数据区,而不是对象的内存空间中。
- 因此,所有对象共享同一个静态成员变量的值。
-
访问方式:
- 可以通过类名和作用域解析运算符
::
来访问静态成员变量,如ClassName::count
。 - 也可以通过对象来访问,但这不是推荐的做法,因为它可能引发误解。
- 可以通过类名和作用域解析运算符
-
用途:
- 常用于计数、记录类的实例数量、作为类内部的全局变量等。
静态成员函数
-
定义与声明:
- 静态成员函数在类内声明时使用
static
关键字,如static void display() {}
。 - 它不属于类的任何对象,因此不能访问非静态成员变量或非静态成员函数(除非通过对象指针或引用传递)。
- 静态成员函数在类内声明时使用
-
调用方式:
- 可以通过类名和作用域解析运算符
::
来调用静态成员函数,如ClassName::display()
。 - 也可以通过对象来调用,但同样不是推荐的做法。
- 可以通过类名和作用域解析运算符
-
参数传递:
- 由于静态成员函数不能访问非静态成员,如果需要访问,通常通过参数传递对象指针或引用。
-
用途:
- 常用于实现与类相关的功能,但不依赖于特定对象的状态。
- 如工厂函数、工具函数等。
面试官追问及相关回答
追问1:
- 问题:静态成员变量和静态成员函数与普通成员变量和成员函数的主要区别是什么?
- 回答:
- 存储位置不同:静态成员变量存储在全局数据区,而普通成员变量存储在对象的内存空间中。
- 访问方式不同:静态成员变量和成员函数可以通过类名直接访问,而普通成员变量和成员函数只能通过对象来访问。
- 生命周期不同:静态成员变量在程序运行时一直存在,直到程序结束;而普通成员变量的生命周期与对象的生命周期相同。
- 作用域不同:静态成员变量和成员函数的作用域是整个类,而普通成员变量和成员函数的作用域是类的实例。
追问2:
- 问题:在嵌入式系统中使用静态成员变量和静态成员函数有哪些需要注意的地方?
- 回答:
- 注意内存使用:由于静态成员变量存储在全局数据区,如果大量使用静态成员变量,可能会导致内存占用过多。
- 避免多线程冲突:在多线程环境中,如果多个线程同时访问同一个静态成员变量,需要采取同步措施来避免数据竞争。
- 谨慎使用静态成员函数访问非静态成员:虽然可以通过参数传递对象指针或引用来访问非静态成员,但这会增加函数的复杂性和出错的可能性。因此,在设计类时,应尽量避免在静态成员函数中访问非静态成员。
追问3:
- 问题:能否给出一个使用静态成员变量和静态成员函数的实际例子?
- 回答:
这个例子展示了如何使用静态成员变量来记录类的实例数量,并使用静态成员函数来显示该数量。class Counter { public: // 静态成员变量,用于记录类的实例数量 static int count; // 构造函数,每次创建对象时增加计数 Counter() { count++; } // 析构函数,每次销毁对象时减少计数 ~Counter() { count--; } // 静态成员函数,用于显示当前计数 static void displayCount() { std::cout << "Current count: " << count << std::endl; } }; // 在类外定义和初始化静态成员变量 int Counter::count = 0; int main() { Counter obj1, obj2; Counter::displayCount(); // 输出:Current count: 2 Counter* obj3 = new Counter(); Counter::displayCount(); // 输出:Current count: 3 delete obj3; Counter::displayCount(); // 输出:Current count: 2 return 0; }
智能指针?
智能指针回答
问题:请解释一下C++中的智能指针,并详细讨论其种类、工作原理以及使用场景。
回答:
智能指针是C++中用于自动管理动态分配内存的一种机制,它通过封装原始指针并提供对资源的自动释放,从而避免了内存泄漏和悬空指针等问题。C++标准库提供了几种主要的智能指针,包括std::unique_ptr
、std::shared_ptr
和std::weak_ptr
。
-
std::unique_ptr:
- 独占所有权的智能指针,不允许复制,只能移动。
- 当
unique_ptr
被销毁或离开作用域时,它所指向的对象也会被自动删除。 - 适用于需要确保只有一个所有者管理资源的场景。
-
std::shared_ptr:
- 共享所有权的智能指针,允许多个
shared_ptr
实例共享同一个对象。 - 使用引用计数机制来管理对象的生命周期,当最后一个
shared_ptr
被销毁或重置时,对象会被自动删除。 - 适用于多个所有者需要共享资源的场景,但需要注意循环引用的问题。
- 共享所有权的智能指针,允许多个
-
std::weak_ptr:
- 弱引用,用于解决
shared_ptr
之间的循环引用问题。 - 不会增加对象的引用计数,因此不会延长对象的生命周期。
- 可以从
shared_ptr
或另一个weak_ptr
创建,但不能直接访问对象,必须通过lock()
方法获取shared_ptr
来临时访问对象。
- 弱引用,用于解决
工作原理:
unique_ptr
通过其析构函数来释放资源,当unique_ptr
对象被销毁时,它会调用delete
来释放其所指向的对象。shared_ptr
使用控制块(通常包含引用计数和指向实际对象的指针)来管理对象的生命周期。当shared_ptr
被复制或赋值时,控制块会被共享,引用计数会增加。当shared_ptr
被销毁或重置时,引用计数会减少。当引用计数变为0时,控制块和对象都会被释放。weak_ptr
不直接管理资源,而是指向shared_ptr
的控制块。它不会增加引用计数,因此不会阻止shared_ptr
所管理的对象被销毁。
使用场景:
unique_ptr
适用于需要确保资源独占所有权的场景,如动态数组、单例模式等。shared_ptr
适用于多个所有者需要共享资源的场景,如对象图、树形结构等。但需要注意避免循环引用。weak_ptr
通常与shared_ptr
一起使用,用于解决循环引用问题,或在不增加引用计数的情况下观察对象的状态。
面试官追问及回答
追问1:
- 问题:请解释一下
std::make_unique
的作用,以及为什么推荐使用它而不是直接使用new
来创建unique_ptr
? - 回答:
std::make_unique
是一个模板函数,用于创建并初始化一个unique_ptr
。它接受与new
相同的参数,并返回一个unique_ptr
对象。- 推荐使用
std::make_unique
而不是直接使用new
来创建unique_ptr
的原因有几个:std::make_unique
更加简洁和直观,它直接返回unique_ptr
,而不需要显式地调用new
。std::make_unique
是异常安全的。如果构造函数抛出异常,它不会泄漏内存,因为new
表达式和unique_ptr
的构造函数是作为一个原子操作执行的。- 使用
std::make_unique
可以避免潜在的内存泄漏问题。如果直接使用new
来创建对象,然后再将其地址赋给unique_ptr
,在赋值过程中如果发生异常,可能会导致内存泄漏。而std::make_unique
则保证了在异常发生时不会泄漏内存。
追问2:
- 问题:在
shared_ptr
和unique_ptr
之间如何选择?请给出一些具体的选择依据。 - 回答:
- 在选择
shared_ptr
和unique_ptr
时,需要考虑资源的所有权和管理方式。 - 如果资源只需要被一个所有者管理,并且不希望其他代码能够访问或共享这个资源,那么应该选择。
- 在选择
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
ARM/Linux嵌入式真题 文章被收录于专栏
让实战与真题助你offer满天飞!!! 每周更新!!! 励志做最全ARM/Linux嵌入式面试必考必会的题库。 励志讲清每一个知识点,找到每个问题最好的答案。 让你学懂,掌握,融会贯通。 因为技术知识工作中也会用到,所以踏实学习哦!!!