乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • C++ 学习路径
  • 第1章 C++概述与开发环境

    • C++ 语言概述与编译模型
    • 第一个 C++ 程序与规范
    • 开发环境配置
    • 预处理指令详解
  • 第2章 基本语法与类型系统

    • 变量与基本类型
    • 类型转换
    • 枚举类型
    • 引用与指针
    • 数组与 stdarray
    • 字符串与原始字符串字面量
    • const 与 constexpr
    • nullptr 与空指针
    • 类型推导 auto 与 decltype
    • 基于范围的 for 循环
    • 值类别全面解析
    • char16_t 与 char32_t
    • static_assert 编译期断言
  • 第3章 函数与重载

    • 函数声明与定义
    • 函数重载
    • 默认参数与内联函数
    • Lambda 表达式
    • 函数对象与 stdfunction
    • 后置返回类型与 noexcept
  • 第4章 类与对象

    • 类的基本定义
    • 构造函数与析构函数
    • 拷贝控制
    • 移动构造函数与移动赋值
    • 列表初始化与类内初始化器
    • 静态成员与嵌套类
    • 友元
    • =default 与 =delete
  • 第5章 继承与多态

    • 继承基础
    • 虚函数与多态
    • 虚函数表与动态绑定原理
    • 虚析构函数
    • 抽象类与纯虚函数
    • 多重继承与虚继承
    • 继承构造函数
  • 第6章 运算符重载

    • 运算符重载基础
    • 算术与关系运算符重载
    • 赋值与移动运算符重载
    • 特殊运算符重载
  • 第7章 模板与泛型编程

    • 函数模板
    • 类模板
    • 模板特化与偏特化
    • 可变参数模板
    • 别名模板与模板模板参数
    • SFINAE 与类型萃取
    • 依赖名与 typename/template 关键字
  • 第8章 异常处理

    • 异常处理机制
    • noexcept 与异常安全
    • RAII 与异常安全实践
  • 第9章 内存管理与智能指针

    • 动态内存与内存分区
    • RAII 惯用法
    • unique_ptr
    • shared_ptr 与 weak_ptr
    • 内存管理最佳实践
  • 第10章 右值引用与移动语义

    • 右值引用与值类别深度解析
    • std::move 原理与使用
    • 完美转发与 std::forward
    • 移动语义性能对比与最佳实践
  • 第11章 STL容器

    • vector 深度剖析
    • deque 内部机制
    • list 与 forward_list
    • map 与 set 深度解析
    • unordered 容器与哈希原理
    • array 与 tuple
    • 容器适配器
    • 容器选择全景指南
  • 第12章 STL算法与迭代器

    • 迭代器体系全解
    • 非变异算法
    • 变异算法
    • 排序与二分算法
    • Lambda 与算法组合
    • std::random 随机数库
    • 自定义迭代器开发
  • 第13章 IO流与文件

    • 标准 IO 流
    • 格式化输出控制
    • 文件流操作
    • 字符串流
    • std::regex 正则表达式
  • 第14章 并发与多线程

    • thread 基础与线程管理
    • mutex 与 lock_guard
    • unique_lock 与 condition_variable
    • thread_local 线程局部存储
    • atomic 与内存序
    • future 与 async 异步编程
    • std::chrono 时间库
  • 第15章 现代C++新特性

    • 从 C++11 到 C++20 演进路线
    • C++14 关键新特性
    • C++17 关键新特性
    • C++20 核心特性速览
  • 第16章 面试考点与最佳实践

    • C++ 综合最佳实践清单
    • 高频面试题精讲
    • 多线程面试题与实战
    • 内存管理常见陷阱与排查
  • 附录

    • C++ 核心知识点
    • C++ 专业术语

类的基本定义

定义与作用

类(Class)是 C++ 面向对象编程的核心机制,它将数据(成员变量)和操作(成员函数)封装为一个逻辑单元。类的设计目标是封装——隐藏内部实现细节,只暴露必要的公共接口。

class Student {
public:             // 公共接口
    void enroll();  // 成员函数
private:            // 内部实现
    std::string name_;
    int id_;
};

核心原理

访问控制与对象布局

const 成员函数与 this 指针

this 是指向当前对象的隐式指针:

  • 非 const 成员函数中:this 类型为 T* const(顶层 const,指针本身不可改)
  • const 成员函数中:this 类型为 const T* const(顶层 + 底层 const)

完整示例

示例一:学生信息管理类

场景说明:设计一个带数据校验的学生类,展示访问控制和 const 正确性。

#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>

class Student {
public:
    // 构造函数
    Student(std::string name, int id, double gpa)
        : name_(std::move(name)), id_(id) {
        setGPA(gpa);  // 通过 setter 复用校验逻辑
    }

    // ---- const 成员函数(只读接口) ----
    const std::string& getName() const { return name_; }
    int getID() const { return id_; }
    double getGPA() const { return gpa_; }

    // 返回等级评定
    std::string getGradeLevel() const {
        if (gpa_ >= 3.7) return "优秀";
        if (gpa_ >= 3.0) return "良好";
        if (gpa_ >= 2.0) return "及格";
        return "不及格";
    }

    // ---- 非 const 成员函数(修改接口) ----
    void setName(std::string name) {
        if (name.empty()) {
            throw std::invalid_argument("姓名不能为空");
        }
        name_ = std::move(name);
    }

    void setGPA(double gpa) {
        if (gpa < 0.0 || gpa > 4.0) {
            throw std::out_of_range("GPA 必须在 0.0 到 4.0 之间");
        }
        gpa_ = gpa;
    }

    // 打印信息
    void print() const {
        std::cout << "姓名: " << name_
                  << " | 学号: " << id_
                  << " | GPA: " << gpa_
                  << " | 等级: " << getGradeLevel() << std::endl;
    }

private:
    std::string name_;
    int id_;
    double gpa_ = 0.0;
};

int main() {
    std::cout << "===== 学生信息管理 =====" << std::endl;

    // 创建对象
    Student alice("张三", 2024001, 3.8);
    alice.print();

    // 修改数据(通过 setter,有校验)
    try {
        alice.setGPA(3.9);
        alice.print();

        alice.setGPA(5.0);  // 触发异常
    } catch (const std::exception& e) {
        std::cerr << "错误: " << e.what() << std::endl;
    }

    // const 对象只能调用 const 成员函数
    const Student const_student("李四", 2024002, 2.5);
    std::cout << "\nconst 学生: " << const_student.getName()
              << " | 等级: " << const_student.getGradeLevel() << std::endl;
    // const_student.setGPA(3.0);  // 编译错误

    return 0;
}

预期输出:

===== 学生信息管理 =====
姓名: 张三 | 学号: 2024001 | GPA: 3.8 | 等级: 优秀
姓名: 张三 | 学号: 2024001 | GPA: 3.9 | 等级: 优秀
错误: GPA 必须在 0.0 到 4.0 之间

const 学生: 李四 | 等级: 及格

逐段分析:

  • getName() 返回 const std::string&:避免拷贝,同时防止外界修改内部数据
  • setGPA() 内置范围校验:封装让数据约束集中管理,不依赖调用者自觉
  • getGradeLevel() 是 const 成员函数——它只读取数据,不修改状态
  • const Student 对象只能调用 const 成员函数——编译器强制执行只读约束
  • 构造函数使用 setGPA() 而非直接赋值——DRY 原则,校验逻辑只写一次

示例二:this 指针与返回 *this 的链式调用

场景说明:设计支持链式调用的 Builder 类,展示 this 指针的实际用法。

#include <iostream>
#include <string>
#include <sstream>

class TableBuilder {
public:
    // 每个 setter 返回 *this,实现链式调用
    TableBuilder& setTitle(std::string title) {
        title_ = std::move(title);
        return *this;  // this 指向当前对象
    }

    TableBuilder& addHeader(std::string header) {
        headers_.append("| ").append(header).append(" ");
        return *this;
    }

    TableBuilder& endHeader() {
        headers_.append("|\n");
        return *this;
    }

    TableBuilder& addRow(std::string cell) {
        rows_.append("| ").append(cell).append(" ");
        return *this;
    }

    TableBuilder& endRow() {
        rows_.append("|\n");
        return *this;
    }

    std::string build() const {
        std::ostringstream oss;
        oss << title_ << "\n";
        oss << headers_.str();
        oss << rows_.str();
        return oss.str();
    }

private:
    std::string title_;
    std::ostringstream headers_;
    std::ostringstream rows_;
};

int main() {
    std::cout << "===== Builder 模式(链式调用) =====" << std::endl;

    // 链式调用:每个方法返回 *this
    TableBuilder builder;
    builder.setTitle("学生成绩表")
           .addHeader("姓名").addHeader("学号").addHeader("GPA").endHeader()
           .addRow("张三").addRow("2024001").addRow("3.8").endRow()
           .addRow("李四").addRow("2024002").addRow("4.0").endRow();

    std::cout << builder.build() << std::endl;

    // 验证 this 指针的值
    std::cout << "===== this 指针验证 =====" << std::endl;
    TableBuilder tb;
    std::cout << "对象地址: " << &tb << std::endl;
    // 每个返回 *this 的方法,返回值地址应该等于 &tb

    return 0;
}

预期输出:

===== Builder 模式(链式调用) =====
学生成绩表
| 姓名 | 学号 | GPA |
| 张三 | 2024001 | 3.8 |
| 李四 | 2024002 | 4.0 |

===== this 指针验证 =====
对象地址: 0x7fff...

逐段分析:

  • 每个 setter 返回 *this 的引用(TableBuilder&),实现方法链(Method Chaining)
  • return *this; 是直接的 this 指针解引用,返回对象自身
  • Builder 模式中链式调用让配置代码紧凑、可读
  • build() 是 const 成员函数——产生最终结果,不修改 Builder 本身

易错场景与面试考点

易错场景

场景错误表现正确做法
const 对象调用非 const 成员函数编译错误将不需要修改状态的成员函数标记为 const
const 成员函数中修改 mutable 成员违反逻辑 const谨慎使用 mutable
忘记 return *this 的引用类型返回值拷贝而非引用返回 T& 而非 T
类声明后忘记分号编译错误class Foo { }; 注意结尾分号
成员函数与自由函数命名冲突意外调用注意作用域,必要时用 this-> 显式调用

常见面试问题

  1. this 指针是什么?类型是什么?何时使用?——指向当前对象的隐式指针。非 const 成员函数中类型 T* const,const 成员函数中 const T* const。用于区分成员变量与局部变量、返回 *this、获取对象地址。

  2. const 成员函数能修改 mutable 成员变量吗?——可以。mutable 成员即使在 const 成员函数中也可修改。典型用途:缓存、互斥锁、引用计数。

  3. 什么函数应该标记为 const?——任何不修改对象逻辑状态的成员函数都应标记为 const。这是 const 正确性(const-correctness)的核心准则。

  4. struct 和 class 的区别?——唯一的区别是默认访问控制:struct 默认 public,class 默认 private。习惯上 struct 用于纯数据聚合,class 用于有封装逻辑的类。

  5. 成员函数可以重载为 const 和非 const 两个版本吗?——可以。例如 T& operator[](int) 和 const T& operator[](int) const。const 对象自动调用 const 版本。

小结

  • 类 = 数据 + 操作的封装单元,核心价值是封装和信息隐藏
  • const 成员函数不修改对象状态,const 对象只能调用 const 成员函数
  • this 是指向当前对象的隐式指针,返回 *this 实现链式调用
  • setter 中加数据校验,让封装保护数据完整性
  • const 正确性是 C++ 代码质量的基石——能 const 就 const
下一页
构造函数与析构函数