注意:全文AI生成


朋友,你是否曾因所学知识的无用而感到迷茫?

又或许,你曾为昔日学习的繁重而深感懊悔?

然而,岁月流转,万物更迭,请坚信“相信”的力量,因为一切终将过时,一切也可能变得看似无用。

昔日,Python以import引领风骚,而今,C++亦步其后尘,采纳了import的优雅。

这变化无常的世界,恰似知识的海洋,波澜壮阔,永不停歇。

让我们以开放的心态,迎接每一个新知,因为今日之无用,或许就是明日之瑰宝。

在学习的道路上,不畏艰难,不惧过时,因为智慧的光芒,永远照亮着前行的路。


// 导出模块BubbleSort  
export module BubbleSort;  
  
// 导入标准库中的vector和算法(如果需要使用std::swap等)  
import <vector>;  
import <algorithm>; // 可选,如果你打算使用std::swap  
  
// 导出冒泡排序函数  
export template<typename T>  
void bubbleSort(std::vector<T>& arr) {  
    bool swapped;  
    do {  
        swapped = false;  
        for (size_t i = 1; i < arr.size(); ++i) {  
            if (arr[i - 1] > arr[i]) {  
                std::swap(arr[i - 1], arr[i]);  
                swapped = true;  
            }  
        }  
    } while (swapped);  
}
// 导入BubbleSort模块  
import BubbleSort;  
  
// 导入标准库中的iostream和vector  
import <iostream>;  
import <vector>;  
  
int main() {  
    // 创建一个整数向量  
    std::vector<int> numbers = {64, 34, 25, 12, 22, 11, 90};  
  
    // 输出排序前的向量  
    std::cout << "Unsorted array: ";  
    for (int num : numbers) {  
        std::cout << num << " ";  
    }  
    std::cout << std::endl;  
  
    // 调用冒泡排序函数  
    bubbleSort(numbers);  
  
    // 输出排序后的向量  
    std::cout << "Sorted array: ";  
    for (int num : numbers) {  
        std::cout << num << " ";  
    }  
    std::cout << std::endl;  
  
    return 0;  
}

那些曾经使用而现在已经改变的技术-C++篇_持续学习

 


在C++20中,Modules机制为代码的组织和重用提供了一种新的方式。虽然Modules主要用于解决编译时间、依赖管理和封装性的问题,但我们仍然可以使用它来编写具体的算法,比如冒泡排序。以下是一个使用C++20 Modules机制实现冒泡排序的示例代码。

首先,我们定义一个模块来包含冒泡排序的实现。为了简化,我们将这个模块命名为BubbleSort

BubbleSort.cppm(模块文件)



cpp

// 导出模块BubbleSort 
export module BubbleSort; 
// 导入标准库中的vector和算法(如果需要使用std::swap等) 
import <vector>; 
import <algorithm>; // 可选,如果你打算使用std::swap 
// 导出冒泡排序函数 
export template<typename T> 
void bubbleSort(std::vector<T>& arr) { 
bool swapped; 
do { 
swapped = false; 
for (size_t i = 1; i < arr.size(); ++i) { 
if (arr[i - 1] > arr[i]) { 
std::swap(arr[i - 1], arr[i]); 
swapped = true; 
} 
} 
} while (swapped); 
}

然后,我们可以在一个主程序中使用这个模块:

main.cpp(主程序文件)



cpp

// 导入BubbleSort模块 
import BubbleSort; 
// 导入标准库中的iostream和vector 
import <iostream>; 
import <vector>; 
int main() { 
// 创建一个整数向量 
std::vector<int> numbers = {64, 34, 25, 12, 22, 11, 90}; 
// 输出排序前的向量 
std::cout << "Unsorted array: "; 
for (int num : numbers) { 
std::cout << num << " "; 
} 
std::cout << std::endl; 
// 调用冒泡排序函数 
bubbleSort(numbers); 
// 输出排序后的向量 
std::cout << "Sorted array: "; 
for (int num : numbers) { 
std::cout << num << " "; 
} 
std::cout << std::endl; 
return 0; 
}

注意

  1. 并不是所有的编译器都支持C++20的Modules机制。你需要确保你的编译器(如GCC、Clang或MSVC)已经实现了这一特性,并且你正在使用支持该特性的编译器版本。
  2. 在编写模块时,文件扩展名可能是.cppm,这是为了区分传统的.cpp源文件。然而,具体的文件扩展名可能因编译器而异;请查阅你的编译器文档以获取更多信息。
  3. 在使用Modules时,你可能需要调整你的构建系统(如Makefile、CMake等)以正确处理模块文件。
  4. 上面的代码示例假设你已经配置好了编译器以支持C++20和Modules。如果你遇到任何编译错误,请检查你的编译器设置和文档以确保你正确地启用了这些特性。

对比

在C++中,传统的头文件(Headers)机制一直是组织和重用代码的基础。然而,随着C++语言的发展,头文件的缺点逐渐显现,如编译时间长、头文件重复包含导致的编译依赖问题等。为了解决这些问题,C++20计划引入Modules这一新特性,以替代传统的头文件机制。以下是对新旧程序案例的对比:

传统头文件机制
优点:
  • 简单易用:开发者通过#include指令可以轻松地包含所需的头文件。
  • 广泛支持:几乎所有的C++编译器都支持头文件机制。
缺点:
  • 编译时间长:头文件中的代码会在每个包含它的源文件中被重复编译,导致编译时间随着项目规模的增大而显著增加。
  • 依赖复杂:头文件之间的依赖关系复杂,修改一个头文件可能会导致多个源文件需要重新编译。
  • 命名冲突:不同头文件中定义的同名标识符可能会产生冲突,需要开发者小心处理。
C++20 Modules机制
优点:
  • 编译速度快:Modules允许编译器将模块编译成中间表示(如IR),并在需要时直接引用这些中间表示,从而避免了重复编译,显著提高了编译速度。
  • 依赖清晰:Modules明确定义了模块之间的依赖关系,使得依赖管理更加清晰和简单。
  • 封装性好:Modules提供了更好的封装性,开发者可以隐藏模块的内部实现细节,只暴露必要的接口。
  • 避免命名冲突:由于Modules之间的隔离性,不同模块中定义的同名标识符不会相互干扰。
缺点:
  • 编译器支持有限:目前,并非所有C++编译器都支持Modules特性。尽管一些主流编译器(如微软的Visual Studio)已经开始支持,但GCC等编译器还在逐步跟进中。
  • 学习曲线:对于习惯了头文件机制的开发者来说,学习和适应Modules机制可能需要一定的时间。

对比案例

假设有一个简单的C++项目,其中包含两个类:PersonStudent,其中Student继承自Person

传统头文件机制

Person.h



#ifndef PERSON_H  
#define PERSON_H  
  
class Person {  
public:  
    Person(std::string name);  
    virtual ~Person();  
    std::string getName() const;  
  
protected:  
    std::string name_;  
};  
  
#endif // PERSON_H

cpp

#ifndef PERSON_H 
#define PERSON_H 
class Person { 
public: 
Person(std::string name); 
virtual ~Person(); 
std::string getName() const; 
protected: 
std::string name_; 
}; 
#endif // PERSON_H

Student.h



#ifndef STUDENT_H  
#define STUDENT_H  
  
#include "Person.h"  
  
class Student : public Person {  
public:  
    Student(std::string name, int grade);  
    int getGrade() const;  
  
private:  
    int grade_;  
};  
  
#endif // STUDENT_H

cpp

#ifndef STUDENT_H 
#define STUDENT_H 
#include "Person.h" 
class Student : public Person { 
public: 
Student(std::string name, int grade); 
int getGrade() const; 
private: 
int grade_; 
}; 
#endif // STUDENT_H

C++20 Modules机制

Person.cppm



export module Person;  
  
import <string>;  
  
export class Person {  
public:  
    Person(std::string name);  
    virtual ~Person();  
    std::string getName() const;  
  
protected:  
    std::string name_;  
};

cpp

export module Person; 
import <string>; 
export class Person { 
public: 
Person(std::string name); 
virtual ~Person(); 
std::string getName() const; 
protected: 
std::string name_; 
};

Student.cppm



export module Student;  
  
import Person; // 导入Person模块  
import <string>;  
  
export class Student : public Person::Person { // 注意这里需要使用模块名和类名来引用基类  
public:  
    Student(std::string name, int grade);  
    int getGrade() const;  
  
private:  
    int grade_;  
};

cpp

export module Student; 
import Person; // 导入Person模块 
import <string>; 
export class Student : public Person::Person { // 注意这里需要使用模块名和类名来引用基类 
public: 
Student(std::string name, int grade); 
int getGrade() const; 
private: 
int grade_; 
};

注意:以上C++20 Modules的示例代码是基于概念性的描述,实际的语法和编译器支持可能会有所不同。

通过对比可以看出,C++20的Modules机制在编译速度、依赖管理和封装性方面相较于传统头文件机制有明显的优势。然而,由于编译器支持有限和学习曲线的问题,开发者在采用Modules机制时需要谨慎考虑。


进化

在C++中,所谓的“格局大”和新概念方式主要体现在其支持多种编程范式(Programming Paradigms)以及不断引入的新特性上。这些编程范式和新特性为C++提供了极大的灵活性和表达能力,使得开发者能够根据具体问题的需求选择最合适的解决方案。以下是一些主要的C++编程范式和新概念方式:

1. 编程范式

1.1 面向过程编程(Procedural Programming)

面向过程编程是一种以函数或过程为中心的编程范式,它关注于通过一系列步骤或函数调用来解决问题。在C++中,面向过程编程是通过函数、条件语句、循环等基本控制结构来实现的。这种范式适用于结构化和顺序性强的问题,如批处理任务、数据转换等。

1.2 面向对象编程(Object-Oriented Programming, OOP)

面向对象编程是C++的核心特性之一,它通过将事物分解成为一个个对象,并由对象之间分工与合作的方式来解决问题。面向对象编程具有封装、继承和多态三大特性,这些特性使得C++能够处理复杂的程序设计和大型项目。封装隐藏了对象的内部状态和实现细节,提高了代码的可维护性和可复用性;继承允许子类继承父类的属性和行为,实现了代码复用;多态则允许不同类的对象被视为同一类对象,增强了程序的灵活性和扩展性。

1.3 泛型编程(Generic Programming)

泛型编程是C++中另一种重要的编程范式,它允许编写与数据类型无关的代码。泛型编程通过模板(Templates)来实现,模板可以定义与数据类型无关的函数和类,然后在编译时根据具体的数据类型生成相应的代码。这种范式在实现算法和数据结构时特别有用,因为它可以极大地减少代码冗余,提高代码的可重用性和灵活性。

1.4 函数式编程(Functional Programming)

虽然C++不是一种纯函数式编程语言,但它支持一些函数式编程的特性,如Lambda表达式、常量表达式(constexpr)以及对不可变数据的操作。Lambda表达式允许创建匿名函数,这对于实现高阶函数和其他函数式编程技术非常有用。常量表达式则允许在编译时计算表达式的值,提高了程序的性能和安全性。

2. 新概念方式

C++不断引入新概念和新特性,以支持更高效的编程和更复杂的应用。以下是一些近年来C++引入的重要新概念:

2.1 Concepts(概念)

C++20引入了Concepts这一新特性,它允许开发者定义模板参数的特性和要求。通过使用Concepts,开发者可以更加清晰地表达模板的约束条件,从而提高代码的可读性和可维护性。此外,Concepts还有助于编译器更早地发现错误,提高编译效率。

2.2 Modules(模块)

C++20还计划引入Modules这一新特性,以替代传统的头文件(Headers)机制。Modules提供了一种更加模块化和封装的方式来组织代码,它有助于减少编译时间和提高代码的安全性。通过Modules,开发者可以将代码划分为独立的模块,每个模块包含一组紧密相关的功能和数据。

2.3 Coroutines(协程)

协程是C++20中引入的另一种重要新特性,它允许开发者以更简洁和直观的方式编写异步代码。协程提供了一种控制流机制,使得函数可以在执行过程中暂停和恢复,而无需使用传统的回调机制或线程。这种机制在处理异步IO、并发编程等领域时非常有用。