Skip to content

1 from C to C++

课程成绩

平时成绩=平时练习*0.6+期中考试*0.3+考勤*0.1
期末考试=期末实验*0.6+期末理论*0.4
总评=期末*0.6+平时*0.4

C++历史

  • 面向对象的特点:
  • 封装、继承和多态
  • 作为抽象数据类型的类
  • 易于调试和维护
  • 是软件开发的主流
  • 一些新增内容:
  • 流式IO操作(std::cin,std::cout)
  • 命名空间
  • 引用
  • const和constexpr

io流

初识对象

  • 什么是对象
  • 对象是现实世界或抽象世界中事物的一种计算机表示。
  • 定义于\<iostream>中有三个对象
  • cin标准输入流,使用stdout输出
  • cout标准输出流,使用stdin输入
  • cerr标准错误流,使用stderr输出

运算符重载

  • C++的大多数运算符都可以重载:根据操作数不同,自定义运算符的操作。例如"<<"">>"是位移运算符,它左右操作数必须是整数。
  • C++形象地将位移运算符用于流对象输入输出操作,例如cout<<"hello"的含义是将hello字符放入stdout输出管道。cin>>aInt是将stdin管道输入按"%d"格式转换后放入变量。
  • "<<" 重载为输出运算
  • 左操作数必须是输出流对象
  • 右操作数是任意类型,编译器会根据右操作数类型选择合适的 fprintf 格式化语句的版本。如右操作数是double,输出格式是"%lf"。
  • 表达式返回左操作数的引用,是左值
  • ">>" 重载为输入运算
  • 左操作数必须是输入流对象
  • 右操作数必须是左值,任意类型。编译自动根据类型使用合适 fscanf
  • 表达式返回左操作数的引用,是左值
  • 输入输出操纵符
  • \<iostream>
  • endl输出'\n'并冲洗输出流
  • dec,hex,oct
  • left,right
  • fixed,scientific
  • showpoint,noshowpoint
  • showpos,noshowpos
  • \<iomanip>
  • setw
  • setprecision

1. 基础控制 (<iostream>)

操纵符 作用 持续性 备注
endl 换行 + 刷新缓冲区 - 频繁使用影响性能
flush 仅刷新缓冲区 - 强制输出,不换行
ws (输入) 跳过前导空白 - 常用于 cin >> ws
dec 十进制 (默认) ✅ 持久 -
hex 十六进制 ✅ 持久 配合 showbase 显示 0x
oct 八进制 ✅ 持久 配合 showbase 显示 0
showbase / noshowbase 显示/隐藏进制前缀 (0x, 0) ✅ 持久 默认隐藏
boolalpha / noboolalpha 布尔显示 true/false1/0 ✅ 持久 默认 1/0
showpoint / noshowpoint 强制/隐藏显示小数点及后随零 ✅ 持久 默认 noshowpoint
uppercase / nouppercase 十六进制/指数大写 (A-F, E) ✅ 持久 默认小写

2. 格式排版 (<iomanip>)

操纵符 参数 作用 持续性 关键提示
setw(n) 整数 设置下一个字段宽度 一次性 每列都要重写
setprecision(n) 整数 设置精度 ✅ 持久 fixed下=小数位; 默认=有效数字
setfill(c) 字符 设置填充字符 ✅ 持久 默认是空格 ' '
left 左对齐 ✅ 持久 配合 setw
right 右对齐 (默认) ✅ 持久 配合 setw
internal 内部对齐 (符号左,数右) ✅ 持久 仅对数值有效
fixed 定点表示法 ✅ 持久 禁止科学计数法
scientific 科学计数法 ✅ 持久 强制 e+ 格式

3. 核心口诀

  • 一次性:只有 setw 是一次性的,其他大多持久。
  • 精度含义fixed + precision = 小数位数;默认 + precision = 总有效位。
  • 性能:循环输出少用 endl,多用 \n
  • 包含:带参数的必须 #include <iomanip>

constexpr

  • 含义编译期常量表达式
  • 作用:强制编译器在编译阶段计算结果,而非运行时。
  • 对比 const
  • const = 运行时只读 (值可来自运行期)。
  • constexpr = 编译期已知 (值必须来自字面量或其他 constexpr)。
  • 核心用途:
  • 替代宏:定义类型安全的常量 (constexpr int N = 10;)。
  • 数组维度int arr[N]; (N 必须编译期已知)。
  • 模板参数std::array<int, N>
  • 性能优化:将复杂计算移至编译期,运行时零开销。

命名空间

  • 在大型项目或使用多个第三方库时,很容易出现两个不同的库定义了相同名称的函数或类的情况。例如,库 A 和库 B 都有一个叫 print() 的函数。如果没有命名空间,编译器就无法区分你调用的是哪一个,导致编译错误。

1. 核心概念

  • 定义:命名空间是 C++ 中用于组织代码、避免命名冲突的机制。
  • 作用:将相关的类、函数、变量等封装在特定的作用域内,防止不同库或模块间出现同名标识符冲突。
  • 类比:就像文件系统中的“文件夹”,不同文件夹下可以有同名文件,通过路径区分。

基本语法

  • 定义命名空间
    namespace MySpace {
        int value = 10;
    
        void show() {
            // 实现代码
        }
    
        class Data {
            // 类定义
        };
    }
    
  • 使用方式
方式 语法示例 特点 推荐度
作用域解析 MySpace::value 最明确,无歧义 ⭐⭐⭐⭐⭐ (首选)
using 声明 using MySpace::show;
show();
仅引入特定名称,安全 ⭐⭐⭐⭐
using 指令 using namespace MySpace;
value = 20;
引入所有名称,易污染作用域 ⭐⭐ (慎用)
  • 嵌套
  • 定义:在已有的命名空间内部再定义新的命名空间,形成层级结构。
  • 类比:文件系统目录结构(如 /home/user/docs),通过层级路径唯一标识资源。
  • C++14及以前
    namespace Company {
      namespace Product {
          namespace Module {
              void init() {
                  // 实现
              }
          }
      }
    }
    
  • C++17及以后
    // C++17 新语法:等价于上面的三层嵌套
    namespace Company::Product::Module {
        void init() {
            // ...
        }
    }
    
    // 调用方式不变
    Company::Product::Module::init();
    

引用

基本概念

  • 定义:引用是某个已存在变量的别名 (Alias)
  • 本质:通过另一个名字访问同一个内存地址。
  • 直观理解:给变量起“绰号”。操作别名等同于操作本体。
  • 关键特性
  • 必须初始化:定义时必须绑定到一个有效变量。
  • 不可重绑定:一旦绑定,终身指向该变量(不能像指针那样改指向)。
  • 非空性:理论上不存在“空引用”(必须绑定对象)。
  • 语法透明:使用时不需要解引用符号(如 *),像普通变量一样操作。
  • 在C++中,尽可能少用指针

注意

  • 引用不是对象。它们可以不占用存储,尽管若需要分配存储以实现所需语义(例如,引用类型的非静态数据成员通常会增加类的大小,量为存储内存地址所需),则由编译器具体实现决定。
  • 因为引用不是对象,故
  • 不存在引用的数组
  • 不存在指向引用的指针
  • 不存在引用的引用
  • C++不存在引用为空的概念,即引用必须被定义
  • 更多要掌握的关于引用概念,参见 cppreference– reference。
    包括:左值引用、右值引用、转发引用、悬垂引用等。
    面试经常涉及,后面课程可能并不讲解!

基本用法

type &别名 =左值表达式

int a = 10;
int &ref = a; // ref 是 a 的引用(别名)

ref = 20;     // 修改 ref,实际上修改了 a
// 此时 a 的值也变成了 20

int b = 30;
// ref = b;   // 错误理解!这不是让 ref 指向 b,而是把 b 的值赋给 a(因为 ref 就是 a)

作为函数返回值

int arr[10];

// 返回数组中某个元素的引用
int& getElement(int index) {
    return arr[index];
}

int main() {
    getElement(0) = 100; // 合法!直接修改 arr[0]
    return 0;
}
注意:返回函数内部的值的引用需要静态变量
double& f( double x )     
{
  static double y;
  y = sin(x);
  return y;
}