C++编程技术全面课程资料包

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:《C++程序大全》为C++学习者提供全面的学习材料,覆盖从基础语法到高级特性的各个层面。资料包内容原创且经典,适合各水平开发者。包括基础语法、面向对象、模板编程、STL库、异常处理、内存管理、输入输出流、多线程编程及C++新特性等多个部分,通过PPT课件、讲义、代码示例和练习题等多种形式的教学资源,帮助学习者逐步构建完整的C++知识体系,并在实践中提升编程技能。 c++程序大全

1. C++基础语法详解

1.1 C++程序结构概述

C++是一种静态类型、编译式语言,它支持面向对象、泛型编程以及过程化编程。一个典型的C++程序包括头文件、函数和数据对象的声明,以及执行实际操作的代码块。理解C++的程序结构是编写有效程序的基础。

1.2 基本数据类型和运算符

C++提供了多种基本数据类型,包括整型、浮点型、字符型和布尔型。每种类型都有对应的字面量表示方式,例如整型的1、浮点型的1.0以及字符型的'A'。运算符是C++语言中的符号,用于表示各种操作,如加减乘除、赋值、逻辑运算等。

1.3 控制流程语句

控制流语句用于控制程序执行的顺序。C++中的控制流程语句包括条件语句(如if-else)和循环语句(如for、while、do-while)。这些语句是构建程序逻辑的基石,使得程序能够根据条件执行不同的代码路径或重复执行代码块,直到满足特定条件。

2. 深入面向对象编程

面向对象编程(OOP)是一种编程范式,它依赖于数据(对象)和代码(类)的抽象,来组织程序的结构。它不仅仅是一组语法,更是一种思考问题的方式,旨在提高软件的模块化、复用性和可维护性。在本章节中,我们将深入探讨面向对象编程的核心概念及其在C++中的实现。

2.1 面向对象的基本概念

2.1.1 类与对象

在C++中,类是一组功能相同或相似的对象的集合。它定义了同一组数据(属性)和操作(方法)的蓝图。对象是类的实例,具有类定义的属性和方法。

class Car {
private:
    int speed;
    string model;
public:
    Car(string m) : model(m) { speed = 0; }
    void drive(int s) { speed = s; }
    int getSpeed() const { return speed; }
};

上面的代码定义了一个名为 Car 的类。 Car 类有两个私有成员变量 speed model ,分别表示汽车的速度和型号。类中还定义了构造函数、 drive 方法和 getSpeed 方法。 Car 类的实例化对象如下:

Car myCar("Tesla Model S");
myCar.drive(60);

在这个例子中, myCar Car 类的一个对象。通过调用 drive 方法,我们可以改变 myCar 的速度。类和对象的概念是面向对象编程的基础。

2.1.2 封装、继承与多态

封装

封装是面向对象编程的三大特征之一,它指的是将数据(或状态)和行为(或功能)捆绑在一起的特性,确保外部对内部的访问是受控制的。通常通过使用类来实现封装。

class Account {
private:
    double balance;
public:
    void deposit(double amount) {
        if (amount > 0) balance += amount;
    }
    double getBalance() const {
        return balance;
    }
};

在这个例子中, balance Account 类的一个私有成员变量,外部代码无法直接访问和修改,而只能通过公共的接口(如 deposit getBalance 方法)来进行操作。

继承

继承是面向对象编程的一个机制,它允许一个类(称为派生类)继承另一个类(称为基类)的属性和方法。继承有助于代码复用,增强了程序的模块化。

class SavingAccount : public Account {
private:
    double interestRate;
public:
    SavingAccount(double rate) : interestRate(rate) {}
    void addInterest() {
        double interest = getBalance() * interestRate / 100;
        deposit(interest);
    }
};

在这个例子中, SavingAccount 类继承了 Account 类,因此它可以访问 Account 类中的成员变量和成员函数。

多态

多态是面向对象编程的另一个重要特征,它允许在派生类中重新定义基类的方法,并在运行时决定调用哪个类的方法。多态是通过虚函数和派生类的重写机制来实现的。

class Shape {
public:
    virtual void draw() = 0;
};

class Circle : public Shape {
public:
    void draw() override {
        // 实现圆形的绘制
    }
};

class Square : public Shape {
public:
    void draw() override {
        // 实现正方形的绘制
    }
};

在这个例子中, Shape 是一个抽象类,它有一个纯虚函数 draw Circle Square 类继承自 Shape 并重写了 draw 方法。这样,通过基类指针可以调用具体对象的方法,从而实现多态。

在下一节中,我们将继续探讨面向对象编程的高级特性。

3. 模板与泛型编程技巧

C++模板编程是其支持泛型编程的重要特征,这使得开发者可以编写与数据类型无关的代码。本章节将深入了解模板的定义与使用、泛型编程实践以及模板元编程的强大能力。

3.1 模板的定义与使用

3.1.1 函数模板

函数模板允许程序员为多种数据类型编写单一的函数实现。编译器将为每一种数据类型生成相应的函数代码。

#include <iostream>

template <typename T>
T add(T a, T b) {
    return a + b;
}

int main() {
    int intSum = add(1, 2);
    double doubleSum = add(1.2, 3.4);
    std::cout << "Sum of integers: " << intSum << std::endl;
    std::cout << "Sum of doubles: " << doubleSum << std::endl;
    return 0;
}

函数模板在编译时,根据实际传入的参数类型,进行模板参数替换。在上面的代码中, add 函数模板根据传入参数的类型,分别生成了处理整型和双精度浮点数的函数。

3.1.2 类模板

类模板用于生成具有相同行为但操作不同类型数据的类。

#include <vector>

template <typename T>
class Stack {
private:
    std::vector<T> elements;

public:
    void push(const T& element) {
        elements.push_back(element);
    }

    void pop() {
        if (!elements.empty()) {
            elements.pop_back();
        }
    }

    T top() const {
        if (!elements.empty()) {
            return elements.back();
        }
        throw std::out_of_range("Stack<>::top(): empty stack");
    }
};

int main() {
    Stack<int> intStack;
    intStack.push(1);
    intStack.push(2);
    intStack.pop();
    return 0;
}

在本例中, Stack 是一个类模板,能够根据不同的类型实例化出不同的堆栈类,例如 intStack 实例化为整型堆栈。

3.2 泛型编程实践

3.2.1 模板特化与偏特化

模板特化允许开发者为模板提供特定类型的专门实现。

template <typename T>
T max(T a, T b) {
    return a > b ? a : b;
}

// 全特化
template <>
const char* max<const char*>(const char* a, const char* b) {
    return strcmp(a, b) > 0 ? a : b;
}

int main() {
    std::cout << "Max of int: " << max(1, 2) << std::endl;
    std::cout << "Max of strings: " << max("hello", "world") << std::endl;
    return 0;
}

模板偏特化是提供模板的部分特化,这在有默认模板参数时特别有用。

3.2.2 标准模板库STL中的泛型算法

STL算法是泛型编程在实际中应用的一个典范,它们可以处理不同类型的容器和元素。

#include <algorithm>
#include <vector>
#include <iostream>

int main() {
    std::vector<int> numbers = {1, 4, 2, 8, 5, 7};
    std::sort(numbers.begin(), numbers.end());
    for (int number : numbers) {
        std::cout << number << " ";
    }
    return 0;
}

在上述代码中, std::sort 是一个泛型算法,它可以对任何类型的容器进行排序,这里演示了对 vector<int> 的排序。

3.3 模板元编程

3.3.1 编译时计算与递归模板元编程

模板元编程(TMP)是一种在编译时进行计算的编程范式。它通过递归模板实例化和特化实现复杂的编译时计算。

template <unsigned int N>
struct Factorial {
    static const unsigned long long value = N * Factorial<N - 1>::value;
};

// 基础情况
template <>
struct Factorial<0> {
    static const unsigned long long value = 1;
};

int main() {
    std::cout << "Factorial of 5: " << Factorial<5>::value << std::endl;
    return 0;
}

3.3.2 类型萃取与编译期策略模式

类型萃取是一种利用模板元编程技术在编译时获取类型信息的技术。编译期策略模式是一种利用类型萃取和模板实现的编译时多态。

template <typename T>
struct remove_reference {
    using type = T;
};

// 特化版本
template <typename T>
struct remove_reference<T&> {
    using type = T;
};

template <typename T>
struct remove_reference<T&&> {
    using type = T;
};

// 使用类型萃取
template <typename T>
void func(T&& arg) {
    using DecayT = typename remove_reference<T>::type;
    // ... do something
}

int main() {
    int x = 5;
    func(x);  // T 是 int &
    func(5);  // T 是 int &&
    return 0;
}

在本节中,我们深入讨论了C++模板的使用和泛型编程实践。从基础的函数模板与类模板开始,逐步探索了模板特化、偏特化,以及模板元编程中的编译时计算和类型萃取。模板编程提供了一种编写灵活、高效且可重用代码的途径,是C++语言强大的特性之一。在下一节中,我们将深入探讨C++标准模板库(STL),了解其核心组件及其在实际开发中的应用。

4. C++标准模板库(STL)深度应用

4.1 STL容器详解

4.1.1 序列式容器

序列式容器按照线性序列的方式组织数据元素,其中最常见的有 vector deque list 。序列式容器的适用场景广泛,它们都支持随机访问迭代器,且各有特点和优劣。

  • vector 是一个动态数组,提供了在序列末尾高效地插入和删除元素的能力,以及快速的随机访问。由于其在内存中连续存储,因此也支持随机访问。对于 vector 的使用,插入和删除元素效率并不是很高,尤其是在非末尾位置插入或删除,会涉及到大量的元素移动操作。
  • deque (双端队列)类似于 vector ,但是它允许在序列的两端高效地插入和删除元素。 deque 是在内存中不连续存储数据的,因此它更适合于需要频繁在两端进行插入和删除操作的应用。

  • list (链表)是一个双向链表结构,支持任意位置的快速插入和删除操作。与 vector deque 相比, list 不支持随机访问,访问元素的时间复杂度为O(n),因为需要通过指针遍历链表。 list 容器提供了双向迭代器。

#include <iostream>
#include <vector>
#include <list>
#include <deque>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::list<int> lst = {1, 2, 3, 4, 5};
    std::deque<int> deq = {1, 2, 3, 4, 5};

    // Insert and erase example for list
    auto it = lst.begin(); // Get an iterator pointing to the beginning
    lst.insert(it, 0); // Insert 0 at the beginning
    lst.erase(it); // Erase the element we just inserted

    // Access elements example for vector
    int thirdElement = vec[2]; // Random access for vector

    // Front and back operations example for deque
    deq.push_back(6); // Add 6 to the end
    deq.push_front(0); // Add 0 to the beginning

    return 0;
}

4.1.2 关联式容器

关联式容器允许存储元素是按特定顺序排序的,如 set multiset map multimap 。这些容器使用红黑树等平衡二叉树结构实现,支持元素的快速查找、插入和删除。

  • set multiset 只包含键值,不允许重复的键;而 multiset 可以有重复的键。它们都提供了有序集合,其中数据元素是根据键排序的。
  • map multimap 存储键值对, map 中不允许重复的键,而 multimap 允许重复的键。
#include <iostream>
#include <set>
#include <map>

int main() {
    std::set<int> mySet;
    mySet.insert(1);
    mySet.insert(2);
    mySet.insert(2); // multiset allows duplicates

    std::map<int, std::string> myMap;
    myMap[1] = "one";
    myMap[2] = "two";
    myMap[3] = "three";

    // Output elements in set
    for (auto const& element : mySet) {
        std::cout << element << ' ';
    }
    std::cout << '\n';

    // Output key-value pairs in map
    for (auto const& element : myMap) {
        std::cout << element.first << ": " << element.second << '\n';
    }

    return 0;
}

4.2 STL算法与迭代器

4.2.1 算法概述与分类

STL算法库提供了一套丰富的模板函数,用于处理序列容器中的元素。这些算法可以被分类为非修改性序列操作、修改性序列操作和排序操作。

  • 非修改性序列操作:例如 count find 等,这类算法不改变容器中的元素。

  • 修改性序列操作:例如 replace copy 等,这类算法会改变容器中的元素。

  • 排序操作:例如 sort merge 等,这类算法会对容器中的元素进行排序。

STL算法通常需要迭代器来指定操作的范围。迭代器是泛型指针,提供了对容器元素的访问机制。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::sort(vec.begin(), vec.end()); // Sort the vector

    // Using find algorithm
    auto it = std::find(vec.begin(), vec.end(), 3); // Find the first occurrence of 3
    if (it != vec.end()) {
        std::cout << "Found " << *it << '\n';
    }

    return 0;
}

4.2.2 迭代器的类型与特性

迭代器的类型决定了它可以执行的操作。迭代器分为以下几种:

  • 输入迭代器:支持单次读取,用于输入序列的遍历。
  • 输出迭代器:支持单次写入,用于输出序列的遍历。
  • 前向迭代器:除了输入迭代器的操作外,还支持多次遍历同一个序列。
  • 双向迭代器:除了前向迭代器的操作外,还可以反向遍历序列。
  • 随机访问迭代器:除了双向迭代器的操作外,还可以像指针一样进行算术运算。

不同类型的STL算法对迭代器的要求各不相同,例如排序算法 sort 需要随机访问迭代器。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // Using a forward iterator
    for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
        std::cout << *it << ' ';
    }
    std::cout << '\n';

    // Using a random access iterator
    std::sort(vec.begin(), vec.end()); // vec.begin() and vec.end() are random access iterators
    for (auto const& element : vec) {
        std::cout << element << ' ';
    }
    std::cout << '\n';

    return 0;
}

4.3 STL实践案例分析

4.3.1 STL在实际编程中的应用

在实际编程中,STL提供了一个高效且易于使用的工具集。例如,当我们需要对一组数据进行排序、查找、统计等操作时,可以使用STL算法和容器来简化代码。

  • 使用 vector sort 对一组数字进行排序。
  • 使用 map 存储和快速查找数据。
  • 使用 list 进行高效地插入和删除操作。
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>

int main() {
    std::vector<int> vec = {5, 3, 2, 4, 1};
    std::sort(vec.begin(), vec.end()); // Sort the vector

    std::map<int, std::string> myMap;
    myMap[1] = "one";
    myMap[2] = "two";
    myMap[3] = "three";

    std::string searchFor = "two";
    auto searchResult = myMap.find(2);
    if (searchResult != myMap.end()) {
        std::cout << "Found " << searchResult->first << ": " << searchResult->second << '\n';
    }

    return 0;
}

4.3.2 性能考量与优化策略

STL的性能优化往往涉及到对容器和算法的正确选择,以及迭代器的高效使用。在选择容器时,应根据实际应用的需求,考虑容器的插入、删除操作的性能影响。例如,频繁在序列末尾插入元素时, vector 可能比 list 更合适。

对于算法的选择,需要关注算法的时间复杂度和空间复杂度。一些算法如 std::sort 可能比手动实现的排序算法更高效。而迭代器的使用也应注意其性能特性,例如对于大型数据结构,使用 const_iterator 可以避免不必要的类型转换,提高效率。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec(1000000); // Large vector
    // Fill the vector with values...

    // Using std::sort which is a highly optimized sorting algorithm
    std::sort(vec.begin(), vec.end());

    return 0;
}

在性能优化方面,还需要关注算法与容器之间的适配性,以及内存使用的优化,例如使用 reserve vector 中提前分配空间,以减少动态扩展时的开销,或者使用 swap 技巧减少不必要的元素复制。

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec1(10000);
    std::vector<int> vec2;

    // Reserve space in vec2 to avoid reallocation
    vec2.reserve(10000);

    // Swap the contents of vec1 and vec2 to move the elements
    vec1.swap(vec2);

    return 0;
}

5. C++的高级特性与现代实践

5.1 C++11及其后续版本的新特性

5.1.1 lambda表达式与自动类型推导

lambda表达式是C++11中引入的一个便捷特性,它允许开发者定义匿名函数对象。Lambda表达式的基本语法为: [捕获列表](参数列表) -> 返回类型 { 函数体 } 。捕获列表定义了lambda表达式可以访问的外部变量。

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    int a = 10;
    // Lambda表达式捕获变量a
    auto lambda = [a](int x) { return x + a; };
    std::cout << lambda(5) << std::endl; // 输出15
    return 0;
}

自动类型推导是指让编译器自动推断变量的类型,C++11中引入了 auto 关键字和 decltype 关键字。 auto 用于自动类型推导,而 decltype 用于查询表达式的类型。

auto x = 5; // x被推导为int类型
decltype(5) y = x; // y也被推导为int类型

5.1.2 智能指针与并发编程

C++11引入了几种智能指针,以帮助管理动态分配的内存。其中, std::unique_ptr 独占资源, std::shared_ptr 允许多个指针共享资源,而 std::weak_ptr 是一种非拥有性智能指针,可以解决 shared_ptr 的循环引用问题。

#include <memory>

void func() {
    auto sp = std::make_shared<int>(42); // 创建shared_ptr
    std::weak_ptr<int> wp = sp; // weak_ptr不增加引用计数
    sp.reset(); // shared_ptr引用计数为0,释放资源
    if (wp.expired()) {
        // 检查资源是否已经释放
        std::cout << "Resource is already released." << std::endl;
    }
}

C++11也提供了并发编程的库,包括线程、互斥锁、原子操作等。 std::thread 是用于创建和管理线程的主要工具。

#include <thread>

void threadFunction() {
    // 线程相关代码
}

int main() {
    std::thread t(threadFunction); // 创建线程
    t.join(); // 等待线程结束
    return 0;
}

智能指针和并发编程是现代C++实践中的关键特性,它们可以提高程序的健壮性和执行效率。

5.2 异常处理机制深入理解

5.2.1 异常类与异常安全编程

异常类是C++中用于处理错误的标准类。当程序遇到一个异常情况时,可以抛出一个异常对象,该对象可以是标准的 std::exception 的子类,也可以是自定义的异常类型。

#include <exception>

class MyException : public std::exception {
public:
    const char* what() const throw() {
        return "MyException occurred!";
    }
};

void mayThrowException() {
    throw MyException();
}

int main() {
    try {
        mayThrowException();
    } catch (MyException& e) {
        std::cerr << e.what() << std::endl;
    }
    return 0;
}

异常安全编程是指编写代码时确保异常发生时,资源被正确地释放和管理。异常安全函数可以保证不会泄漏资源,不会破坏对象的不变性。

5.2.2 异常规范与最佳实践

异常规范(Exception Specifications)在C++11之前用来说明函数是否会抛出异常。C++11开始废弃了这个特性,因为它被认为是一个失败的尝试,实际中常常引起诸多问题。

最佳实践包括: - 使用智能指针管理资源,减少资源泄露风险。 - 定义异常安全的接口和实现。 - 在公共接口中避免使用异常规范,而是使用文档说明异常行为。

5.3 动态内存管理与智能指针

5.3.1 new/delete与内存泄漏

new delete 是C++中用于动态分配和释放内存的操作符。它们提供了比C语言中 malloc free 更高级的内存管理功能。

int* p = new int(42); // 动态分配内存并初始化
delete p; // 释放内存

虽然 new delete 提供了灵活性,但不当的使用容易导致内存泄漏。内存泄漏是指程序中已分配的内存无法再被释放,导致内存逐渐耗尽。

5.3.2 shared_ptr、unique_ptr与weak_ptr

智能指针是C++标准库提供的自动化内存管理工具,有助于防止内存泄漏。

std::shared_ptr 可以共享对象的所有权。当最后一个 shared_ptr 被销毁时,它所管理的对象将被删除。

#include <memory>

int main() {
    auto sp = std::make_shared<int>(42); // 创建shared_ptr
    {
        auto sp2 = sp; // sp2和sp共享所有权
    } // sp2离开作用域,被销毁,但对象仍然存在
    // sp离开作用域,对象被正确地删除
    return 0;
}

std::unique_ptr 独占对象所有权。当 unique_ptr 被销毁时,它所管理的对象也会被销毁。

std::weak_ptr 不拥有对象,它允许访问 shared_ptr 所管理的对象,但不增加引用计数。当 shared_ptr 被销毁时, weak_ptr 可以安全检查对象是否存在。

5.4 输入/输出流操作

5.4.1 输入输出流库的架构与组件

C++的输入/输出流库(通常称为iostream库)提供了一套丰富的接口用于数据的输入和输出。它主要包含三个部分:iostream、fstream、sstream。iostream处理标准输入输出,fstream处理文件输入输出,sstream处理内存中的字符串输入输出。

#include <iostream>
#include <fstream>
#include <sstream>

int main() {
    std::cout << "Hello, World!" << std::endl; // 标准输出
    std::ifstream fileIn("input.txt"); // 文件输入流
    std::ofstream fileOut("output.txt"); // 文件输出流
    std::stringstream buffer; // 字符串流
    buffer << "Hello, Stream!" << std::flush; // 写入数据到内存
    return 0;
}

5.4.2 文件操作与流缓冲区控制

文件操作是流库中重要的部分,它允许程序读取和写入文件。

#include <fstream>

int main() {
    std::ofstream file("example.txt"); // 打开文件用于写入
    if (!file.is_open()) {
        std::cerr << "Unable to open file for writing" << std::endl;
        return 1;
    }
    file << "This is an example" << std::endl; // 写入数据
    file.close(); // 关闭文件
    return 0;
}

流缓冲区控制允许程序更细致地管理数据流。比如,可以手动刷新输出流缓冲区:

std::cout << "Writing to cout." << std::flush;

5.5 多线程编程的C++实现

5.5.1 线程创建与管理

多线程编程允许程序同时执行多个操作,C++11引入了 std::thread 类来支持多线程编程。创建线程的方法是实例化一个 std::thread 对象,并将一个可调用对象(函数或lambda表达式)传递给它。

#include <thread>

void doWork() {
    // 执行任务
}

int main() {
    std::thread t(doWork); // 创建线程
    t.join(); // 等待线程结束
    return 0;
}

5.5.2 同步机制与线程安全数据结构

同步机制是多线程编程中重要的组成部分。C++11提供了互斥锁( std::mutex )、条件变量( std::condition_variable )等同步机制。线程安全数据结构要求在设计时考虑到并发读写,确保数据的一致性和完整性。

#include <mutex>
#include <thread>

std::mutex m;
int sharedResource = 0;

void increment() {
    for (int i = 0; i < 1000; ++i) {
        m.lock();
        ++sharedResource;
        m.unlock();
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join();
    t2.join();
    std::cout << "Shared resource value: " << sharedResource << std::endl;
    return 0;
}

5.6 设计模式在C++中的应用

5.6.1 设计模式基本概念与分类

设计模式是软件开发中解决特定问题的一般性方案。在C++中,设计模式可以用来提高代码的可重用性、可维护性和可扩展性。设计模式主要分为以下三类:

  • 创建型模式:如单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。
  • 结构型模式:如适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式、代理模式。
  • 行为型模式:如责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式。

5.6.2 C++实现设计模式案例分析

以观察者模式为例,C++中可以使用 std::function std::bind 来实现。观察者模式定义了对象之间的一对多依赖关系,当一个对象改变状态时,所有依赖于它的对象都会收到通知并自动更新。

#include <functional>
#include <iostream>
#include <list>

class Observer {
public:
    virtual void update(int data) = 0;
};

class Subject {
    std::list<Observer*> observers;
    int data;
public:
    void attach(Observer* o) {
        observers.push_back(o);
    }
    void notify() {
        for (Observer* o : observers) {
            o->update(data);
        }
    }
    void setData(int data) {
        this->data = data;
        notify();
    }
};

class ConcreteObserver : public Observer {
    int data;
public:
    void update(int d) override {
        data = d;
        std::cout << "ConcreteObserver has new data: " << data << std::endl;
    }
};

int main() {
    Subject subject;
    ConcreteObserver observer1, observer2;
    subject.attach(&observer1);
    subject.attach(&observer2);
    subject.setData(10);
    subject.setData(20);
    return 0;
}

以上案例展示了如何在C++中实现和应用观察者模式。通过这种模式,可以减少耦合度,使得各个组件之间更加独立,提高了软件系统的可维护性和扩展性。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:《C++程序大全》为C++学习者提供全面的学习材料,覆盖从基础语法到高级特性的各个层面。资料包内容原创且经典,适合各水平开发者。包括基础语法、面向对象、模板编程、STL库、异常处理、内存管理、输入输出流、多线程编程及C++新特性等多个部分,通过PPT课件、讲义、代码示例和练习题等多种形式的教学资源,帮助学习者逐步构建完整的C++知识体系,并在实践中提升编程技能。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值