实习冲刺练习 第二十四天
每日一题
多数元素. - 力扣(LeetCode)
class Solution {
public:
int majorityElement(vector<int>& nums) {
sort(nums.begin(),nums.end());//先排序,找到中间的值就是多数元素
return nums[nums.size()/2];
}
};
八股
什么是 C++ 内联函数?它的作用是什么?
内联函数是一种通过提示编译器在调用该函数时将函数的代码直接嵌入到调用点的机制,从而减少函数调用开销的方法。
作用与特点
- 减少函数调用开销:在普通函数调用中,程序需要保存上下文信息、跳转到函数地址、执行函数代码并返回结果,而内联函数通过将函数体嵌入调用点,可以省去这些操作,从而提高性能。
- 适用于小型函数:内联函数通常用于代码量小、逻辑简单的函数(例如 getter、setter、计算函数等),以减少函数调用带来的开销。
- 可能增加代码体积(代码膨胀):由于内联函数在每次调用时都将被替换为实际的函数代码,如果调用次数多,且函数体较大,会导致编译后的程序体积变大。
- 编译器优化:inline 只是对编译器的建议,编译器可能会根据实际情况决定是否内联。
- 允许定义在头文件中:内联函数可以直接定义在头文件中,因为内联函数在调用点被展开,不会导致重复定义问题。
内联函数与普通函数有什么区别?如何定义和使用内联函数?
内联函数与普通函数的区别
比较项目 | 内联函数 | 普通函数 |
---|---|---|
调用方式 | 函数调用时,编译器将函数代码直接嵌入到调用点,不需要函数调用开销。 | 通过函数调用指令执行,存在参数压栈、跳转和返回等开销。 |
关键字 | 使用 inline 关键字定义,或者直接在类中定义(隐式内联)。 | 无需使用任何特殊关键字。 |
代码存储 | 函数体代码嵌入调用点,多个调用点可能会重复生成相同代码,导致程序体积变大。 | 函数体代码只定义一次,所有调用点通过跳转共享这段代码。 |
适用场景 | 适用于代码量小、逻辑简单、频繁调用的函数(如 getter/setter 或小型工具函数)。 | 适用于复杂逻辑、大量代码或不适合内联优化的场景(如递归、循环等)。 |
递归支持 | 不支持递归函数作为内联函数,因为递归的展开是无限的。 | 完全支持递归。 |
调试和优化 | 嵌入到调用点后,可能难以调试,代码阅读也变得复杂;现代编译器可能忽略 inline 提示。 | 调试较为简单,调用点明确。 |
使用头文件 | 定义在头文件中不会产生重复定义错误,因为函数体嵌入在调用点处编译。 | 如果定义在头文件中,可能因重复定义而导致链接错误(需要 extern 声明)。 |
定义和使用内联函数
定义方法
- 显式内联:在函数定义前加
inline
关键字。 - 隐式内联:直接在类定义中实现成员函数。
显式
#include <iostream>
inline int multiply(int a, int b) {
return a * b;
}
int main() {
int x = 3, y = 4;
std::cout << "Product: " << multiply(x, y) << std::endl; // 调用内联函数
return 0;
}
隐式
#include <iostream>
class Rectangle {
public:
// 在类定义中实现的成员函数是隐式内联的
int area(int width, int height) { return width * height; }
};
int main() {
Rectangle rect;
std::cout << "Area: " << rect.area(5, 6) << std::endl; // 调用内联函数
return 0;
}
使用方式
- 声明和定义在一起:内联函数需要在声明处提供函数的完整定义,通常写在头文件中。
- 调用方式与普通函数相同:调用时,程序员看不到任何区别,编译器自动决定是否内联展开。
- 适用于简单逻辑的场景:内联函数应避免复杂逻辑或过长的代码,通常用于频繁调用的小函数。