【C++ Primer】第十九章:特殊工具与技术

特殊工具与技术涵盖了 C++ 中一些高级和特殊的特性,这些工具在特定场景下非常强大。

1. 控制内存分配

重载 new 和 delete

#include <new>
#include <iostream>

class MemoryDemo {
private:
    static std::size_t alloc_count;
    static std::size_t total_allocated;
    
public:
    // 重载类特定的 operator new
    static void* operator new(std::size_t size) {
        ++alloc_count;
        total_allocated += size;
        std::cout << "Custom new: allocating " << size 
                  << " bytes (total: " << total_allocated << ")" << std::endl;
        
        if (void* ptr = ::operator new(size)) {
            return ptr;
        }
        throw std::bad_alloc();
    }
    
    // 重载类特定的 operator delete
    static void operator delete(void* ptr) noexcept {
        std::cout << "Custom delete" << std::endl;
        ::operator delete(ptr);
    }
    
    // 重载数组版本
    static void* operator new[](std::size_t size) {
        std::cout << "Custom new[]: allocating " << size << " bytes" << std::endl;
        return ::operator new[](size);
    }
    
    static void operator delete[](void* ptr) noexcept {
        std::cout << "Custom delete[]" << std::endl;
        ::operator delete[](ptr);
    }
    
    // 不抛出异常的版本
    static void* operator new(std::size_t size, std::nothrow_t) noexcept {
        std::cout << "Custom new (nothrow)" << std::endl;
        return ::operator new(size, std::nothrow);
    }
    
    static void operator delete(void* ptr, std::nothrow_t) noexcept {
        std::cout << "Custom delete (nothrow)" << std::endl;
        ::operator delete(ptr, std::nothrow);
    }
    
    static void print_stats() {
        std::cout << "Allocations: " << alloc_count 
                  << ", Total bytes: " << total_allocated << std::endl;
    }
};

std::size_t MemoryDemo::alloc_count = 0;
std::size_t MemoryDemo::total_allocated = 0;

void memory_allocation_demo() {
    MemoryDemo::print_stats();
    
    // 使用自定义 new/delete
    MemoryDemo* obj = new MemoryDemo;
    delete obj;
    
    MemoryDemo* array = new MemoryDemo[3];
    delete[] array;
    
    // 使用 nothrow 版本
    MemoryDemo* nothrow_obj = new (std::nothrow) MemoryDemo;
    delete nothrow_obj;
    
    MemoryDemo::print_stats();
}

定位 new 表达式

#include <cstdlib>

class PlacementNewDemo {
private:
    int value;
public:
    PlacementNewDemo(int v) : value(v) {
        std::cout << "Constructing PlacementNewDemo with value: " << value << std::endl;
    }
    
    ~PlacementNewDemo() {
        std::cout << "Destroying PlacementNewDemo with value: " << value << std::endl;
    }
    
    void print() const {
        std::cout << "Value: " << value << std::endl;
    }
};

void placement_new_demo() {
    // 预分配内存
    alignas(PlacementNewDemo) char buffer[sizeof(PlacementNewDemo)];
    
    // 在指定内存位置构造对象
    PlacementNewDemo* obj = new (buffer) PlacementNewDemo(42);
    obj->print();
    
    // 必须显式调用析构函数
    obj->~PlacementNewDemo();
    
    // 重用内存
    PlacementNewDemo* obj2 = new (buffer) PlacementNewDemo(100);
    obj2->print();
    obj2->~PlacementNewDemo();
}

2. 运行时类型识别(RTTI)深入

typeid 操作符

#include <typeinfo>

class RTTIBase {
public:
    virtual ~RTTIBase() = default;
    virtual void identify() const {
        std::cout << "I am RTTIBase" << std::endl;
    }
};

class RTTIDerived : public RTTIBase {
public:
    void identify() const override {
        std::cout << "I am RTTIDerived" << std::endl;
    }
    
    void derived_method() const {
        std::cout << "Derived specific method" << std::endl;
    }
};

void typeid_demo() {
    RTTIBase* base_ptr = new RTTIDerived;
    
    // 使用 typeid 获取类型信息
    std::cout << "typeid(*base_ptr).name(): " << typeid(*base_ptr).name() << std::endl;
    std::cout << "typeid(RTTIDerived).name(): " << typeid(RTTIDerived).name() << std::endl;
    
    // 比较类型
    if (typeid(*base_ptr) == typeid(RTTIDerived)) {
        std::cout << "base_ptr points to RTTIDerived object" << std::endl;
    }
    
    if (typeid(*base_ptr) != typeid(RTTIBase)) {
        std::cout << "base_ptr does NOT point to RTTIBase object" << std::endl;
    }
    
    delete base_ptr;
    
    // 内置类型的 typeid
    int x = 42;
    double y = 3.14;
    std::cout << "typeid(int): " << typeid(x).name() << std::endl;
    std::cout << "typeid(double): " << typeid(y).name() << std::endl;
}

dynamic_cast 深入

class Animal {
public:
    virtual ~Animal() = default;
};

class Mammal : public virtual Animal {
public:
    virtual void breathe() {
        std::cout << "Mammal breathing" << std::endl;
    }
};

class Winged {
public:
    virtual void fly() {
        std::cout << "Flying" << std::endl;
    }
};

class Bat : public Mammal, public Winged {
public:
    void echolocate() {
        std::cout << "Bat echolocating" << std::endl;
    }
};

void dynamic_cast_demo() {
    Bat bat;
    Animal* animal_ptr = &bat;
    Mammal* mammal_ptr = &bat;
    
    // 向上转换总是安全的
    Animal* animal_from_bat = dynamic_cast<Animal*>(&bat);
    
    // 向下转换 - 检查类型
    Bat* bat_from_animal = dynamic_cast<Bat*>(animal_ptr);
    if (bat_from_animal) {
        std::cout << "Successful downcast from Animal to Bat" << std::endl;
        bat_from_animal->echolocate();
    }
    
    // 交叉转换
    Winged* winged_from_mammal = dynamic_cast<Winged*>(mammal_ptr);
    if (winged_from_mammal) {
        std::cout << "Successful crosscast from Mammal to Winged" << std::endl;
        winged_from_mammal->fly();
    }
    
    // 引用转换(失败会抛出异常)
    try {
        Bat& bat_ref = dynamic_cast<Bat&>(*animal_ptr);
        bat_ref.echolocate();
    } catch (const std::bad_cast& e) {
        std::cout << "Bad cast: " << e.what() << std::endl;
    }
}

3. 类成员指针

数据成员指针

class Employee {
public:
    std::string name;
    int id;
    double salary;
    
    Employee(const std::string& n, int i, double s) 
        : name(n), id(i), salary(s) {}
    
    void print() const {
        std::cout << "Employee: " << name << " (ID: " << id 
                  << ", Salary: " << salary << ")" << std::endl;
    }
};

void data_member_pointer_demo() {
    Employee emp("John Doe", 123, 75000.0);
    
    // 定义成员指针
    std::string Employee::*name_ptr = &Employee::name;
    int Employee::*id_ptr = &Employee::id;
    double Employee::*salary_ptr = &Employee::salary;
    
    // 通过成员指针访问
    std::cout << "Name: " << emp.*name_ptr << std::endl;
    std::cout << "ID: " << emp.*id_ptr << std::endl;
    std::cout << "Salary: " << emp.*salary_ptr << std::endl;
    
    // 通过指针访问
    Employee* emp_ptr = &emp;
    std::cout << "Via pointer - Name: " << emp_ptr->*name_ptr << std::endl;
    
    // 成员指针数组
    using MemberPtr = std::string Employee::*;
    MemberPtr members[] = {&Employee::name};
    
    for (auto ptr : members) {
        std::cout << "Array access: " << emp.*ptr << std::endl;
    }
}

成员函数指针

class Calculator {
public:
    double add(double a, double b) const {
        return a + b;
    }
    
    double multiply(double a, double b) const {
        return a * b;
    }
    
    double divide(double a, double b) const {
        if (b == 0) throw std::invalid_argument("Division by zero");
        return a / b;
    }
    
    static double static_method(double x) {
        return x * x;
    }
};

void member_function_pointer_demo() {
    Calculator calc;
    
    // 成员函数指针类型
    using MemberFuncPtr = double (Calculator::*)(double, double) const;
    
    // 定义成员函数指针
    MemberFuncPtr add_ptr = &Calculator::add;
    MemberFuncPtr multiply_ptr = &Calculator::multiply;
    MemberFuncPtr divide_ptr = &Calculator::divide;
    
    // 通过成员函数指针调用
    std::cout << "5 + 3 = " << (calc.*add_ptr)(5, 3) << std::endl;
    std::cout << "5 * 3 = " << (calc.*multiply_ptr)(5, 3) << std::endl;
    std::cout << "6 / 2 = " << (calc.*divide_ptr)(6, 2) << std::endl;
    
    // 静态成员函数指针
    using StaticFuncPtr = double (*)(double);
    StaticFuncPtr static_ptr = &Calculator::static_method;
    
    std::cout << "static_method(4) = " << static_ptr(4) << std::endl;
    
    // 成员函数指针表
    struct Operation {
        std::string name;
        MemberFuncPtr func;
    };
    
    Operation operations[] = {
        {"Addition", &Calculator::add},
        {"Multiplication", &Calculator::multiply},
        {"Division", &Calculator::divide}
    };
    
    for (const auto& op : operations) {
        try {
            double result = (calc.*op.func)(10, 2);
            std::cout << op.name << ": " << result << std::endl;
        } catch (const std::exception& e) {
            std::cout << op.name << " failed: " << e.what() << std::endl;
        }
    }
}

4. 嵌套类

基本嵌套类

class LinkedList {
private:
    struct Node {
        int data;
        Node* next;
        
        Node(int value) : data(value), next(nullptr) {}
    };
    
    Node* head;
    std::size_t size;
    
public:
    // 嵌套迭代器类
    class Iterator {
    private:
        Node* current;
        
    public:
        Iterator(Node* node) : current(node) {}
        
        // 解引用操作符
        int& operator*() {
            return current->data;
        }
        
        // 前置递增
        Iterator& operator++() {
            if (current) {
                current = current->next;
            }
            return *this;
        }
        
        // 后置递增
        Iterator operator++(int) {
            Iterator temp = *this;
            ++(*this);
            return temp;
        }
        
        // 比较操作符
        bool operator==(const Iterator& other) const {
            return current == other.current;
        }
        
        bool operator!=(const Iterator& other) const {
            return !(*this == other);
        }
    };
    
public:
    LinkedList() : head(nullptr), size(0) {}
    
    ~LinkedList() {
        while (head) {
            Node* temp = head;
            head = head->next;
            delete temp;
        }
    }
    
    void push_front(int value) {
        Node* new_node = new Node(value);
        new_node->next = head;
        head = new_node;
        ++size;
    }
    
    // 迭代器接口
    Iterator begin() {
        return Iterator(head);
    }
    
    Iterator end() {
        return Iterator(nullptr);
    }
    
    std::size_t get_size() const {
        return size;
    }
};

void nested_class_demo() {
    LinkedList list;
    list.push_front(3);
    list.push_front(2);
    list.push_front(1);
    
    std::cout << "LinkedList contents: ";
    for (LinkedList::Iterator it = list.begin(); it != list.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    
    // 使用范围for循环(需要合适的begin/end)
    std::cout << "Using auto: ";
    for (auto it = list.begin(); it != list.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
}

5. 位域

位域的基本使用

class BitFieldDemo {
private:
    // 位域声明
    unsigned int is_ready : 1;      // 1 bit
    unsigned int priority : 3;      // 3 bits (0-7)
    unsigned int status : 2;        // 2 bits (0-3)
    unsigned int : 2;               // 未命名的填充位
    unsigned int counter : 8;       // 8 bits (0-255)
    
public:
    BitFieldDemo() : is_ready(0), priority(0), status(0), counter(0) {}
    
    void set_ready(bool ready) {
        is_ready = ready ? 1 : 0;
    }
    
    bool get_ready() const {
        return is_ready != 0;
    }
    
    void set_priority(unsigned int prio) {
        if (prio > 7) prio = 7;  // 限制在3位范围内
        priority = prio;
    }
    
    unsigned int get_priority() const {
        return priority;
    }
    
    void set_status(unsigned int stat) {
        if (stat > 3) stat = 3;  // 限制在2位范围内
        status = stat;
    }
    
    unsigned int get_status() const {
        return status;
    }
    
    void increment_counter() {
        if (counter < 255) {
            ++counter;
        }
    }
    
    unsigned int get_counter() const {
        return counter;
    }
    
    void print() const {
        std::cout << "Ready: " << get_ready()
                  << ", Priority: " << get_priority()
                  << ", Status: " << get_status()
                  << ", Counter: " << get_counter() << std::endl;
    }
};

void bitfield_demo() {
    BitFieldDemo demo;
    
    demo.print();
    
    demo.set_ready(true);
    demo.set_priority(5);
    demo.set_status(2);
    
    for (int i = 0; i < 10; ++i) {
        demo.increment_counter();
    }
    
    demo.print();
    
    // 大小信息
    std::cout << "Size of BitFieldDemo: " << sizeof(BitFieldDemo) 
              << " bytes" << std::endl;
}

6. volatile 限定符

volatile 的使用

class VolatileDemo {
private:
    volatile int sensor_value;  // 可能被硬件修改
    volatile bool data_ready;   // 可能被中断服务程序修改
    
public:
    VolatileDemo() : sensor_value(0), data_ready(false) {}
    
    // 模拟硬件读取
    int read_sensor() {
        // 模拟传感器值变化
        return ++sensor_value;
    }
    
    // 等待数据就绪
    void wait_for_data() {
        while (!data_ready) {
            // 空循环 - 编译器不会优化掉对volatile变量的检查
        }
        std::cout << "Data is ready!" << std::endl;
    }
    
    // 设置数据就绪标志
    void set_data_ready() {
        data_ready = true;
    }
    
    // 演示volatile在内存映射IO中的使用
    void memory_mapped_io_demo() {
        // 假设这是硬件寄存器地址
        volatile uint32_t* hardware_register = reinterpret_cast<volatile uint32_t*>(0x12345678);
        
        // 读取硬件寄存器
        uint32_t status = *hardware_register;
        
        // 写入硬件寄存器
        *hardware_register = 0xABCD;
        
        std::cout << "Hardware register demo completed" << std::endl;
    }
};

void volatile_demo() {
    VolatileDemo demo;
    
    // 演示多次读取volatile变量
    std::cout << "Sensor readings: ";
    for (int i = 0; i < 5; ++i) {
        std::cout << demo.read_sensor() << " ";
    }
    std::cout << std::endl;
    
    // 在另一个线程中设置数据就绪标志
    std::thread setter([&demo]() {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        demo.set_data_ready();
    });
    
    demo.wait_for_data();
    setter.join();
}

7. 链接指示符:extern “C”

C 和 C++ 混合编程

// C 头文件模拟 (math_utils.h)
#ifdef __cplusplus
extern "C" {
#endif

// C 风格的函数声明
double c_sqrt(double x);
double c_power(double base, double exponent);
void c_print_message(const char* message);

#ifdef __cplusplus
}
#endif

// C++ 实现使用 C 函数
void extern_c_demo() {
    std::cout << "Using C functions from C++:" << std::endl;
    
    // 调用 C 函数
    double result1 = c_sqrt(25.0);
    double result2 = c_power(2.0, 3.0);
    
    std::cout << "sqrt(25) = " << result1 << std::endl;
    std::cout << "2^3 = " << result2 << std::endl;
    
    c_print_message("Hello from C++!");
}

// 模拟 C 函数的实现
extern "C" {
    double c_sqrt(double x) {
        return sqrt(x);
    }
    
    double c_power(double base, double exponent) {
        return pow(base, exponent);
    }
    
    void c_print_message(const char* message) {
        std::cout << "C function says: " << message << std::endl;
    }
}

8. 实践项目:内存池分配器

#include <memory>
#include <vector>

template<typename T>
class MemoryPool {
private:
    struct Block {
        union {
            T object;
            Block* next;
        };
    };
    
    std::vector<std::unique_ptr<Block[]>> chunks;
    Block* free_list;
    std::size_t chunk_size;
    
    void allocate_chunk() {
        auto new_chunk = std::make_unique<Block[]>(chunk_size);
        chunks.push_back(std::move(new_chunk));
        
        // 将新块添加到空闲列表
        for (std::size_t i = 0; i < chunk_size; ++i) {
            chunks.back()[i].next = free_list;
            free_list = &chunks.back()[i];
        }
    }
    
public:
    MemoryPool(std::size_t chunk_size = 64) 
        : free_list(nullptr), chunk_size(chunk_size) {}
    
    // 禁用拷贝
    MemoryPool(const MemoryPool&) = delete;
    MemoryPool& operator=(const MemoryPool&) = delete;
    
    template<typename... Args>
    T* construct(Args&&... args) {
        if (!free_list) {
            allocate_chunk();
        }
        
        Block* block = free_list;
        free_list = free_list->next;
        
        // 在内存位置构造对象
        return new (&block->object) T(std::forward<Args>(args)...);
    }
    
    void destroy(T* object) {
        // 调用析构函数
        object->~T();
        
        // 将内存块返回给空闲列表
        Block* block = reinterpret_cast<Block*>(object);
        block->next = free_list;
        free_list = block;
    }
    
    std::size_t chunk_count() const {
        return chunks.size();
    }
};

// 测试类
class PooledObject {
private:
    int id;
    std::string name;
    
public:
    PooledObject(int i = 0, const std::string& n = "") 
        : id(i), name(n) {
        std::cout << "Constructing PooledObject " << id << std::endl;
    }
    
    ~PooledObject() {
        std::cout << "Destroying PooledObject " << id << std::endl;
    }
    
    void print() const {
        std::cout << "PooledObject: id=" << id << ", name=" << name << std::endl;
    }
};

void memory_pool_demo() {
    MemoryPool<PooledObject> pool;
    
    // 使用内存池分配对象
    PooledObject* obj1 = pool.construct(1, "First");
    PooledObject* obj2 = pool.construct(2, "Second");
    PooledObject* obj3 = pool.construct(3, "Third");
    
    obj1->print();
    obj2->print();
    obj3->print();
    
    std::cout << "Chunks allocated: " << pool.chunk_count() << std::endl;
    
    // 返回到内存池
    pool.destroy(obj1);
    pool.destroy(obj2);
    pool.destroy(obj3);
    
    // 重用内存
    PooledObject* obj4 = pool.construct(4, "Reused");
    obj4->print();
}

最佳实践总结

  1. 谨慎重载 new/delete,确保正确性
  2. 合理使用 RTTI,优先考虑虚函数
  3. 位域适合存储标志和状态信息
  4. volatile 用于硬件访问和信号处理
  5. extern “C” 用于 C/C++ 混合编程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值