有C语言基础再学C++,第二章给我的感觉是:**大部分都眼熟,但仔细一看,又好像哪里不太一样。
int还是那个int,float还是那个float,但C++在C的基础上,给数据类型和表达式加了不少"buff"。这篇就聊聊从C转C++时,第二章里那些让我眼前一亮(或者一头雾水)的知识点。
一、似曾相识:C里就有的东西
先快速过一遍,C语言里已经有的数据类型和运算符,C++基本都保留了:
**基本数据类型 **:short、int、long、long long、float、double、long double、char
**运算符 **:算术、关系、逻辑、位运算、赋值、三目运算符
隐式类型转换 、 强制类型转换
sizeof运算符
这些和C基本一样,该怎么用还怎么用。有C基础的话,这部分看一眼就能捡起来。
二、C++新增的类型特性

  1. bool 类型:终于有正经布尔了!
    在C语言里,我们用0表示假,非0表示真,虽然也能用,但总觉得不那么"优雅"。C++终于有了专门的 bool 类型,只有两个值:true 和 false。
    bool is_ok = true;
    bool is_error = false;

bool 类型的大小是 1 字节。虽然C99其实也有 _Bool 和 <stdbool.h>,但用起来不如C++这么原生支持得彻底——C++里 bool 是关键字,直接用,不用包含头文件。
一个小细节 :
bool a = 100; // true(非零转bool都是true
int b = true; // 1(bool转int,true是1,false是0
2. const:从"只读变量"到"真正的常量"
这是C和C++里const最大的区别!
**C语言里的const **:本质上是一个"不能被修改的变量",有自己的存储空间,不能当数组大小不能用const变量:
// C语言里
const int n = 10;
int arr[n]; // 错误!n是变量,不能用来定义数组大小

**C++里的const **:更像"常量",编译器会尽量把它编译成常量(类似#define),可以用来定义数组大小:
// C++里
const int n = 10;
int arr[n]; // 可以!n是编译期常量

这就是为什么C++里推荐用const代替#define定义常量——类型安全,有作用域,还能调试。
重点区分 :C++的const更安全又分两种:
编译期const :用常量表达式初始化的,编译器直接替换成常量
运行期const :用变量初始化的,就是只读变量
const int a = 10; // 编译期常量
int x = 5;
const int b = x; // 运行期const,不能用来定义数组会报错
3. auto 类型推导:懒人福音
C++11引入的auto,让编译器自动帮你推导出变量的类型:
auto a = 10; // int
auto b = 3.14; // double
auto c = ‘a’; // char
auto d = true; // bool

刚开始用的时候觉得"这有啥用啊",后来发现类型名越长越香。
特别是类型名很长的时候,比如迭代器:
// 不用auto的写法
std::vector::iterator it = vec.begin();
// 用auto的写法
auto it = vec.begin();
少打好多字!而且不容易写错。
三、C++的类型转换:四种命名转换
C语言里的强制转换 (类型)值 虽然强大但太粗暴了——啥都能转,出了问题也不好排查。
C++引入了四种命名的强制转换,各管一摊,更安全也更清晰:

  1. static_cast —— 静态转换
    最常用的,用于明确定义的转换:
    int a = 10;
    double b = static_cast(a); // int转double
    void *p = &a;
    int *q = static_cast<int >§; // void转具体类型指针

不能转掉无关类型的指针转换(比如int转double),比C风格安全一些。
2. const_cast —— 去掉const属性
专门用来去掉(或加上)const属性:
const int *p = &a;
int *q = const_cast<int *>§; // 去掉const
这个要慎用!去掉const去修改原来的话,如果原对象本来就不是const的才安全。如果原对象本身就是const的,修改是未定义行为。
3. reinterpret_cast —— 重新解释比特
最危险的一种,任意指针之间乱转,比如int转指针之类的:
int a = 10;
char p = reinterpret_cast<char >(&a); // int转char
uintptr_t addr = reinterpret_cast<uintptr_t>(&a); // 指针转整数
不到万不得已别用。底层编程(写驱动、搞内存操作的时候可能会用到。
四、运算符的变化

  1. 新增的运算符
    C++加了几个C没有的运算符:
    :: 作用域解析运算符
    new / delete 动态内存分配
    .* / ->* 成员指针运算符(后面讲类的时候
    typeid 运行时类型识别
    这些后面章节会细讲,第二章先混个脸熟。
  2. 运算符重载
    C++支持运算符重载,就是让自定义类型也能用+、-、==这些运算符。这个是C++面向对象的一大特性,但第二章一般不讲
    后面讲。
  3. 三目运算符的区别
    C里三目运算符返回右值,不能当左值。C++里三目运算符可以当左值(如果两个操作数都是左值的话):
    int a = 10, b = 20;
    (a > b ? a : b) = 100; // C++里可以,把大的那个赋值为100
    虽然这个特性虽然很酷,但实际用得不多,知道就行。
    五、从C转C++的注意事项
  4. 尽量用C++的头文件
    C的头文件在C++里也能用,但C++有自己的版本:
    表格
    C头文件 C++头文件
    `#include <stdio.h> #include
    #include <math.h> #include
    #include <string.h> #include
    #include <stdlib.h> #include
    C++版本的头文件里的函数都在 std 命名空间里。
  5. 用 const 代替 #define
    C++里定义常量推荐用 const 或 constexpr,不推荐用 #define:
    const 有类型检查,更安全
    有作用域限制
    调试的时候能看到变量名
    #define 是预处理替换,没有类型检查,容易出问题。
  6. C++更强调类型检查更严格
    C++的类型检查比C严格多了,比如:
    void* 不能隐式转换成其他类型指针(C可以)
    函数必须有返回类型(C里默认int)
    枚举类型不能和int随便转(C可以随意转)
    void *p = malloc(100);
    int *q = p; // C里可以,C++报错
    // C++必须显式转换
    int q = static_cast<int>§;
    刚开始觉得麻烦,习惯了会发现——严格的检查帮你提前发现好多bug。
    六、学习心得
  7. 不用从零开始,有C基础上手很快
    C++的基础数据类型和C大部分一样,不用重新学一遍。重点看不一样的地方就好。
  8. C++是个"多范式"语言
    从C的面向过程,到C++的面向对象、泛型编程…C++提供了好多工具,不一定要全用上,但得知道有这些东西。
  9. 安全第一
    C++在C的基础上,加了好多安全特性(const、命名转换、类型检查),就是为了让你写出更安全的代码。
    写在最后
    有C基础学C++的好处是:基础不用从零开始,坏处是:容易带着C的思维写C++代码。
    慢慢调整心态,把C++当一门新语言来学,会发现很多新东西的乐趣和便利的。

更多推荐