C++中的易混点3

一、前言

还有3天,今天仍是巩固的一天~

二、易混点

  • C++中带默认参数的函数原型
    int f(int x,int y=20,int z=30);		// 默认参数必须从右向左设置
    int f(int x,int y=20,int z);		// ❌
    int f(int x=10,int y=20,int z);		// ❌
    
  • 类和对象
    • 类只是一个蓝图/模板,编译后是代码段的一部分。只有创建对象时才会分配内存
    • 类的定义(包括成员函数)存储在代码区,不占用对象的内存空间
  • 构造函数
    • 函数名和类名相同
    • 没有返回类型
    • 可以被重载
  • 析构函数
    • 没有返回值
    • 不接受参数(不能重载)
    • 对于给定类,只有唯一的一个析构函数
  • 多态
    • 静态多态(编译时多态)

      实现机制:函数重载,模板,运算符重载

      编译时我就知道调用什么函数

    • 动态多态(运行时多态)

      实现机制:虚函数机制实现,相同的接口,不同的行为。

      接口就那一个,显示不出来什么,只有在运行时才能溯源

  • 前置和后置运算符重载
    // 前置
    class Student {
    private:
        int score;
    public:
        // 前置--:无参数
        Student& operator--() {
            --score;
            return *this;
        }
    };
    
    // 使用
    Student s;
    --s;  // 调用 operator--()
    
    // 后置
    class Student {
    private:
        int score;
    public:
        // 后置--:有一个int参数(仅用于区分,实际不使用)
        Student operator--(int) {
            Student temp = *this;
            --score;
            return temp;  // 返回原值的副本
        }
    };
    
    // 使用
    Student s;
    s--;  // 调用 operator--(int)
    
  • 友元
    • 不是类的成员函数
    • 没有this指针通过参数对象访问成员
    • 需要在类内声明,类外定义
  • 静态函数为什么不能被定义为纯虚函数
    1. 技术冲突:静态函数(编译期绑定)与虚函数(运行期多态)机制矛盾
    2. 语义冲突:静态函数属于类,纯虚函数需要对象多态
    3. vtable机制:静态函数不参与虚函数表,无法实现动态绑定
  • switch

    switch的表达式和case标签必须是整型枚举类型

    int(整型),long long(长整型),char(char本质是1字节整型(ASCII码值))

  • sizeof(string)

    典型范围:24、28 或 32 字节(64位系统)

    与内容无关:无论字符串多长,sizeof结果相同

    不是固定值,取决于编译器实现

    表示:string对象本身的栈内存大小

  • sizeof(字符数组)

    // 未指定具体大小
    char n[] = "hello";  // 编译器自动推断大小为6
    
    // 内存中的实际存储:
    // n[0] = 'h'
    // n[1] = 'e' 
    // n[2] = 'l'
    // n[3] = 'l'
    // n[4] = 'o'
    // n[5] = '\0'  // 字符串结束符
    
    // 多维数组
    char names[][10] = {"Alice", "Bob", "Charlie"};  // 3个字符串,每个最多10字符
    
    cout << sizeof(names) << endl;        // 输出:30(3 × 10)
    cout << sizeof(names[0]) << endl;     // 输出:10(每个子数组大小)
    
    // 指定了大小
    char n[10];                    // 声明大小为10的字符数组
    cout << sizeof(n) << endl;     // 输出:10
    
    char n2[100] = "hello";        // 声明大小为100,初始化"hello"  
    cout << sizeof(n2) << endl;    // 输出:100(不是5!)
    
  • 常成员函数
    int max(int,int) const;
    
  • 手动调析构函数
    1. 手动调用析构函数后,该对象的析构函数在退出作用域时仍然会被自动调用
    2. 这会导致双重析构,通常是严重的编程错误
    3. 只有在特定场景下(如placement new)才应该手动调用析构函数
  • 指针VS引用
    • 指针可以在定义后任意改变指向

    • 引用在初始化后就不能改变指向(绑定是永久的)

      int a = 1, b = 2;
      
      int* p = &a;  // p指向a
      p = &b;       // ✅ p现在指向b(改变指向)
      
      int& r = a;   // r是a的别名  
      r = b;        // ❌ 这不是改变指向,而是 a = b
      
  • C++文件打开模式

    ios::app

    • 所有写入自动追加到文件末尾
    • 不能移动文件指针
    • 文件不存在时自动创建
    • 文件存在时保留原有内容

    ios::ate:at end

    • 打开时文件指针定位到末尾
    • 可以自由移动文件指针到任意位置
    • 文件存在时保留内容
    • 文件不存在时行为取决于其他模式

    ios::trunc截断模式(Truncate)

    • 打开时立即清空文件内容
    • 文件大小变为0
    • 通常与ios::out一起使用
    • 文件不存在时创建新文件

    ios::in输入流不会自动创建文件

    ios::out

    • 文件不存在时,就创建文件
    • 文件存在时,就清空内容
    • 指针位置在开头
    • 指针可移动

    ios_base::in :打开以读取

    ios_base::out | ios_base::trunc : 打开以写入,如果已经存在,则删除其中原有的内容

    ios_base::out | ios_base::app : 打开以写入,只追加(不能移动文件指针)

    ios_base::out | ios_base::ate : 打开以写入,打开时定位到文件末尾,但可以移动到任意位置读写

  • C++中的文件操作

    iostream:输入输出流基类

    ifstreamofstream:文件流,这两个组合起来就是fstream

    ofstream:读操作的文件类

    ifstream:写操作的文件类

    fstream:可同时读写操作的文件类,继承iostream

三、小结

关于文件操作不太熟。。。

每次看同样的东西,总会有新的收获与感悟~要常常回顾

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐