声明 VS 定义
区别
特性 | 声明 | 定义 |
---|---|---|
内存分配 | 不分配内存 | 分配内存 |
功能 | 提供类型信息,对编译器声明名称 | 声明并创建实际的变量或函数实现 |
示例 | extern int x; / int add(int, int); | int x; / int add(int a, int b) { /*...*/ } |
注意事项
- 变量的声明和定义: 在 C 语言中,变量的声明和定义通常是在一个地方完成的,但可以分开。例如,一个变量可以在一个文件中声明,并在另一个文件中定义。
- 函数可以多次声明: 函数可以有多个声明,但只能有一个定义。
- extern 关键字: 用于进行声明,将变量定义在其他文件中。
typedef VS using
特性 | typedef | using |
---|---|---|
语法 | 较为复杂,尤其是对于复杂类型 | 更简洁和直观 |
可读性 | 对复杂类型可读性差 | 提高了可读性 |
模板支持 | 不支持 | 支持模板类型别名 |
特性组合 | 无法与其他新特性结合 | 能与 decltype 等结合 |
兼容性 | 兼容所有 C/C++ 版本 | 仅在 C++11 及以上支持 |
decltype VS auto
区别:
特性 | decltype | auto |
---|---|---|
用法 | 返回表达式的类型 | 自动推导变量的类型 |
语法 | decltype(expression) | auto variable_name = expression; |
评估 | 不会计算表达式的值 | 会计算表达式的值并确定类型 |
引用 | 保留引用性 | 不保留引用性,变量会是值语义 |
使用场景
decltype 特别适用于以下情况:
- 模板编程: 在写模板时,获取类型以支持泛型编程。
- 返回类型: 利用 decltype 可以轻松定义复杂函数的返回类型。
- 类型推导: 在需要获得复杂表达式的类型时非常方便。
auto 使用场景
使用场景 | 描述 | 示例代码 |
---|---|---|
简化类型声明 | 自动推导复杂类型,以减少冗长的类型声明。 | std::vector<std::pair<int, double>> vec;``for (auto it = vec.begin(); it != vec.end(); ++it) {...} |
返回类型推导 | 省略函数返回类型,同时保持类型的清晰。 | auto myVector = getVector(); |
Lambda 表达式 | 用于定义匿名函数,简化参数及返回类型的声明。 | auto lambda = [](int a, int b) -> auto { return a + b; }; |
避免冗长或复杂的类型 | 尤其适用于 STL 容器和多重嵌套的复杂类型。 | for (auto& pair : myMap) {...} |
Ranges (C++20) | 在使用 ranges 时,使代码更为简洁。 | for (auto n : filtered) {...} |
模板编程 | 在模板中使用 auto 使得函数定义更灵活。 | template <typename T> auto add(T a, T b) {...} |
与 decltype 结合使用 | 在结合使用 decltype 时,可以实现高灵活性的类型推导。 | decltype(auto) func() {...} |
与引用结合使用 | 使用 auto& 可声明引用类型,避免不必要的拷贝。 | auto& ref = x; |
函数指针 VS std::function
特性 | 函数指针 | std::function |
---|---|---|
定义 | 指向具有特定签名的函数的指针 | 封装任意可调用对象(函数、Lambda 等) |
性能 | 通常更快 | 可能存在性能开销 |
灵活性 | 只能指向特定类型(签名匹配) | 可以存储多种类型 |
类型安全 | 类型检查较少,可能导致未定义行为 | 提供严格的类型检查 |
支持的对象类型 | 仅支持普通函数 | 支持 Lambda、成员函数、函数对象等 |
语法 | 语法简单 | 语法相对复杂 |
适用场景 | 简单场景,如回调 | 复杂场景,如事件处理和模板编程 |