• 类的定义

    类是C++面向对象编程的基本构建块,它将数据和操作数据的函数封装在一起。

    类的基本语法

    类的组成部分

    数据成员(属性)

    成员函数(方法)

    访问修饰符

    C++提供了三种访问修饰符来控制类成员的访问权限:

    对象创建

    对象的创建是面向对象编程的基础操作。

    栈上创建对象

    栈上创建的对象会在超出作用域时自动销毁。

    堆上创建对象

    堆上创建的对象需要手动释放内存。

    构造函数

    默认构造函数

    带参数的构造函数

    初始化列表

    对象创建的其他方式

    拷贝构造

    移动构造(C++11)

    列表初始化(C++11)

    静态创建与动态创建的区别

    特性栈上创建(静态)堆上创建(动态)
    内存管理自动手动
    生命周期作用域结束时销毁由程序员控制
    大小限制受栈大小限制受可用内存限制
    性能较快较慢
    适用场景小对象,临时对象大对象,长生命周期对象

    对象数组的创建

    对象销毁

    对象的销毁是C++内存管理的重要环节,与对象创建相对应。

    栈上对象的销毁

    栈上创建的对象会在超出其作用域时自动销毁。

    堆上对象的销毁

    堆上创建的对象需要手动释放内存。

    析构函数

    析构函数是对象销毁时自动调用的特殊成员函数,用于释放资源。

    对象销毁的顺序

    局部对象

    局部对象的销毁顺序与创建顺序相反(后进先出)。

    成员对象

    类的成员对象销毁顺序与初始化顺序相反,与声明顺序无关。

    继承关系中的对象

    派生类对象销毁时,先调用派生类的析构函数,再调用基类的析构函数。

    虚析构函数

    当通过基类指针删除派生类对象时,需要虚析构函数确保正确调用派生类的析构函数。

    对象数组的销毁

    拷贝构造函数

    拷贝构造函数是C++中一种特殊的构造函数,用于创建一个对象的副本。它在对象需要复制时被调用,是C++中实现对象复制的重要机制。其形式为:

    其中other是同类型的另一个对象的引用,通常声明为常量引用。

    调用时机

    拷贝构造函数在以下情况下会被调用:

    1. 用一个对象初始化另一个对象

    2. 函数按值传递对象参数

    3. 函数按值返回对象

    默认拷贝构造函数

    如果没有显式定义拷贝构造函数,编译器会提供一个默认的拷贝构造函数,执行浅拷贝(逐成员复制)。

    自定义拷贝构造函数

    当类包含动态分配的资源时,需要自定义拷贝构造函数实现深拷贝。

    浅拷贝与深拷贝

    浅拷贝

    深拷贝

    拷贝构造函数与赋值运算符的区别

    禁用拷贝构造函数

    在某些情况下,可能需要禁止对象的复制:

    赋值运算符函数

    赋值运算符函数是C++中的一种特殊成员函数,用于定义对象之间的赋值行为。它在已经存在的对象之间进行赋值操作时被调用。

    赋值运算符函数的形式为:

    其中other是要赋值的源对象,返回类型通常是当前类的引用,以支持连续赋值。

    默认赋值运算符

    如果没有显式定义赋值运算符,编译器会提供一个默认的赋值运算符,执行浅拷贝(逐成员复制)。

    自定义赋值运算符

    当类包含动态分配的资源时,需要自定义赋值运算符实现深拷贝。

    赋值运算符的关键要点

    自我赋值检查

    防止对象赋值给自己时出现问题:

    异常安全

    确保在分配新资源失败时不会丢失原有资源:

    返回*this

    返回对象自身的引用,支持连续赋值:

    赋值运算符与拷贝构造函数的区别

    禁用赋值运算符

    在某些情况下,可能需要禁止对象的赋值:

    特殊数据成员

    C++类中有几种特殊的数据成员,它们具有特殊的性质和用途。

    静态数据成员(Static Data Members)

    静态数据成员是属于类而非对象的成员变量,所有对象共享同一个静态数据成员。

    特点:

    常量数据成员(Const Data Members)

    常量数据成员是在对象创建后不能修改的成员变量。

    特点:

    引用数据成员(Reference Data Members)

    引用数据成员是对其他对象的引用。

    特点:

    特殊的成员函数

    静态成员函数(Static Member Functions)

    静态成员函数是属于类而非对象的函数,它们可以在不创建类的实例的情况下被调用。

    特点

    1. 不依赖对象实例:静态成员函数不与任何对象关联,可以通过类名直接调用

    2. 没有this指针:由于不依赖对象实例,静态成员函数没有this指针

    3. 只能访问静态成员:静态成员函数只能访问类的静态成员(静态数据成员和其他静态成员函数)

    4. 不能声明为const:静态成员函数不能被声明为const、volatile或virtual

    5. 不能使用非静态数据成员:不能直接访问类的非静态数据成员

    语法

    应用场景

    1. 计数器:记录类创建了多少个实例

    2. 工厂方法:创建类的实例

    3. 单例模式:确保类只有一个实例

    4. 工具函数:提供与类相关但不需要对象状态的功能

    const成员函数(Const Member Functions)

    const成员函数是承诺不会修改对象状态的成员函数,通过在函数声明后加const关键字实现。

    特点

    1. 不能修改对象状态:const成员函数不能修改非mutable的数据成员

    2. 可以用于const对象:const对象只能调用const成员函数

    3. this指针为const:在const成员函数中,this指针是指向const对象的指针

    4. 可以重载:可以基于const限定符重载成员函数

    5. 可以修改mutable成员:即使在const成员函数中,也可以修改声明为mutable的成员

    语法

    应用场景

    1. 访问器函数:获取对象状态但不修改它

    2. 查询操作:执行不改变对象状态的操作

    3. const对象的方法:允许const对象调用的方法

    4. 线程安全:在多线程环境中表明函数不会修改共享数据

    两者的比较

    特性静态成员函数const成员函数
    调用方式通过类名或对象只能通过对象
    this指针没有const this指针
    访问限制只能访问静态成员可以访问所有成员,但不能修改非mutable成员
    对象要求不需要对象实例可以被const和非const对象调用
    主要用途与类相关但不依赖对象状态的功能不修改对象状态的操作

    单例模式

    单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例。

    单例模式的核心思想是:

    单例模式的实现方式

    懒汉式(延迟初始化)

    特点:

    饿汉式(立即初始化)

    特点:

    线程安全的懒汉式(双检锁)

    特点:

    Meyers单例(C++11推荐)

    特点:

    单例模式的销毁

    使用智能指针

    使用嵌套类作为析构器

    单例模式的优缺点

    优点:

    缺点:

    std::string

    C++风格字符串是指C++标准库中的std::string类,它是对C风格字符串的封装和扩展,提供了更安全、更方便的字符串处理方式。

    std::string是C++标准库中的字符串类,定义在<string>头文件中,属于std命名空间。

    创建和初始化

    基本操作

    字符串连接

    访问字符

    字符串长度和容量

    子字符串

    查找和替换

    插入和删除

    比较

    与C风格字符串的转换

    C++字符串转C风格字符串

    C风格字符串转C++字符串

    字符串流

    字符串转换

    C++风格字符串与C风格字符串的比较

    特性std::stringC风格字符串
    内存管理自动手动
    边界检查支持(at方法)不支持
    动态调整大小支持不支持
    字符串操作丰富的成员函数需要使用库函数
    连接操作使用+运算符需要使用strcat等函数
    安全性低(容易缓冲区溢出)

    std::vector

    std::vector是C++标准模板库(STL)中最常用的容器之一,它实现了动态数组的功能,能够自动管理内存并提供丰富的操作接口。

    std::vector是一个模板类,定义在<vector>头文件中,属于std命名空间。它提供了一个可以动态增长的数组,具有以下特点:

    创建和初始化

    基本操作

    添加和删除元素

    访问元素

    大小和容量

    迭代器

    常用算法

    std::vector可以与STL算法库一起使用:

    二维vector

    与C风格数组的比较

    特性std::vectorC风格数组
    大小可动态调整固定
    内存管理自动手动
    边界检查支持(at方法)不支持
    功能丰富的成员函数和算法基本操作
    性能略有开销最高效
    安全性

    vector的底层实现

    vector在底层通常由三个指针(或迭代器)组成:

    1. start:指向数组中第一个元素的位置

    2. finish:指向最后一个元素之后的位置(past-the-end)

    3. end of storage:指向分配内存的末尾

    内存管理策略

    vector使用连续的内存块来存储元素,这使得它能够提供随机访问的能力。当创建一个空的vector时,通常不会立即分配内存,而是在添加第一个元素时才分配。

    当vector需要更多空间时(例如通过push_back添加元素),它会:

    1. 分配一个更大的新内存块(通常是当前容量的1.5倍或2倍,具体倍数取决于实现)

    2. 将现有元素复制或移动到新内存

    3. 释放旧内存

    4. 更新指针

    这种策略确保了push_back操作的均摊时间复杂度为O(1)。

    当vector被销毁或调用clear()方法时,它会销毁所有元素并释放分配的内存。resize()shrink_to_fit()也可能导致内存重新分配。

    简化的vector实现示例

    注意事项

    1. 迭代器失效:在修改vector时,迭代器可能会失效

    2. 引用失效:当vector重新分配内存时,之前的引用会失效

    3. 使用reserve避免频繁重新分配