嵌入式八股 - C++ 一
1、C++中如果一个类被继承,那么它的析构函数会怎么处理?
在继承中,对象的析构顺序与构造顺序是相反的,遵循先构造的后析构的原则。先调用派生类的析构函数,而后调用基类的析构函数。
2、引用和指针区别
1)引用
- 引用本身是变量的别名,不占用额外内存空间
- 引用必须在声明时进行初始化(不能为空)
- 引用一旦初始化不能再改变其指向
- 引用可以像普通变量一样直接使用,无需解引用
- 引用不能进行自增自减操作
- 使用sizeof时返回它所引用的对象本身的大小
注意:使用引用时往往是避免额外的拷贝开销!
2)指针
- 指针是指向变量地址,本身占用额外内存空间
- 指针在声明时可以不初始化,但是强烈建议初始化(不然野指针)
- 指针可以在初始化后修改指针指向
- 指针需要使用*进行解引用以访问对象
- 指针可以进行自增自减操作
- 使用sizeof时返回指针本身的大小
3、左值与右值
左值指有明确内存地址的对象,而右值指临时的没有明确内存地址的对象。
其区分的关键在于对象有无分配内存地址,可否使用&取地址。
4、左值引用和右值引用
1)左值引用
在 C++ 中,左值引用 是一种引用类型,它绑定到一个左值。左值引用使用 & 符号声明,主要用于别名或避免对象拷贝。
- 普通左值引用 (
T&):只能绑定到非 const 的左值。它不能绑定到字面量、临时对象等右值。 - 常左值引用 (
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++内也有访问权限的区别,支持
public、private和protected关键字; - C中struct定义变量时必须写上
struct关键字,而C++中编译器会自动把结构体名当作类型名,直接声明即可。 - C中struct不支持继承,而C++支持继承和多态。
9、C++ 中 struct和Class区别是什么?
- 默认访问权限不同: struct 的默认访问权限是
public,而 class 的默认权限是private。 - 默认继承方式不同:struct 继承时默认是
public继承,而 class 的继承时默认是private继承。
10、什么是深拷贝、什么是浅拷贝
- 浅拷贝是指只复制其值,不分配新内存空间;
- 深拷贝是指分配新内存空间并且复制其值。
涉及嵌入式全方面知识。根据个人学习以及面试所得,并且加上自己见解、理解记忆方法。