首页 > 编程语言 >C++入门

C++入门

时间:2024-09-30 12:22:29浏览次数:7  
标签:std 函数 示例 int cout C++ 入门

第1节:开发环境的搭建与配置

1.1 目标

在本节课中,学生将学习如何在Windows上搭建一个现代化的C++开发环境,并使用VSCode和CMake工具进行C++程序的开发与调试。学生将掌握以下内容:

  • 安装VSCode及C++插件
  • 安装MinGW或其他C++编译器
  • 安装并配置CMake
  • 创建并编译第一个C++项目
  • 使用VSCode调试C++程序

1.2 工具准备

  • VSCode:一个开源的跨平台文本编辑器,具有强大的插件支持和内置调试功能。
  • MinGW其他C++编译器:提供在Windows下的GCC编译工具链。
  • CMake:一个跨平台的构建工具,可以生成适用于不同平台的构建文件。
步骤1:安装VSCode
  1. 打开VSCode官方网站,下载适用于Windows的安装包。
  2. 按照提示完成安装,选择默认设置。
  3. 安装完成后,启动VSCode。
步骤2:安装C++插件
  1. 在VSCode主界面的左侧扩展图标点击,打开扩展市场。
  2. 搜索C++,找到C/C++插件(由Microsoft发布),点击安装。
  3. 安装完成后,VSCode会提示重启编辑器,按照提示操作。
步骤3:安装MinGW或其他编译器
  1. 打开MinGW官方网站,下载并安装MinGW。
  2. 安装过程中,确保选中g++编译器组件。
  3. 安装完成后,配置系统环境变量:
    • 右键“此电脑”,选择“属性” -> “高级系统设置” -> “环境变量”。
    • 在“系统变量”中,找到并编辑Path变量,添加MinGW的bin路径(例如C:\MinGW\bin)。
  4. 打开命令提示符,输入g++ --version验证安装是否成功。
步骤4:安装CMake
  1. 打开CMake官方网站,下载适用于Windows的安装包。
  2. 按照默认选项进行安装,并确保在安装过程中选中了"Add CMake to the system PATH"选项,以便CMake命令行工具能够全局访问。
  3. 安装完成后,打开命令提示符,输入cmake --version,检查是否安装成功。
步骤5:配置VSCode的C++开发环境
  1. 启动VSCode,按Ctrl+Shift+P打开命令面板,输入CMake: Quick Start,并按回车。
  2. 选择一个文件夹作为项目目录。
  3. 输入项目名称(例如HelloWorld)。
  4. 选择C++作为项目语言,继续选择最适合的编译器工具链。
  5. VSCode会自动生成一个基本的CMake项目结构,包括CMakeLists.txt文件。
步骤6:编写第一个C++程序
  1. src文件夹中,创建一个名为main.cpp的文件,输入以下代码:
    #include <iostream>
    
    int main() {
        std::cout << "Hello, World!" << std::endl;
        return 0;
    }
    
  2. 保存文件。
步骤7:编译与运行程序
  1. 在VSCode中,点击左侧活动栏中的CMake Tools图标,选择Build,CMake会生成构建文件并编译项目。
  2. 当编译完成后,点击Run运行生成的可执行文件,你将会在VSCode的终端窗口中看到输出结果:Hello, World!
步骤8:调试C++程序
  1. 点击左侧活动栏中的调试图标,点击“创建launch.json文件”并选择C++调试器。
  2. launch.json文件中,VSCode会自动生成适合C++项目的调试配置。
  3. 设置断点(在代码行号处点击)。
  4. 点击开始调试,程序将会在断点处暂停,允许你检查变量和执行流。

1.3 小结

通过本节课的学习,学生已经成功搭建了一个现代C++开发环境,并使用VSCode、CMake和MinGW编译、运行了第一个C++程序。同时,学生也初步掌握了如何在VSCode中进行调试操作。

第2节:C++基础语法与结构

2.1 目标

本节课将引导学生了解C++的基础语法,包括程序的基本结构、数据类型、变量、输入输出以及条件语句的使用。通过本节课的学习,学生将能够编写简单的C++程序,并理解C++程序的运行方式。

2.2 基本概念

2.2.1 C++程序的基本结构

C++程序的基本结构通常包含以下部分:

  1. 预处理指令:如#include <iostream>,用于引入标准库。
  2. 主函数:C++程序从main()函数开始执行。
  3. 语句:每个语句以分号结尾。

示例代码:

#include <iostream>

int main() {
    std::cout << "Welcome to C++!" << std::endl;
    return 0;
}
2.2.2 数据类型、变量与常量
  • 数据类型:C++提供了多种基本数据类型,如intfloatdoublecharbool等。
  • 变量:用来存储不同类型的数据,必须在使用前声明。
  • 常量:使用const关键字声明,其值不可更改。

示例代码:

int main() {
    int age = 20;
    float height = 1.75;
    const int year = 2024;
    std::cout << "Age: " << age << ", Height: " << height << ", Year: " << year << std::endl;
    return 0;
}
2.2.3 输入与输出
  • std::cout用于输出信息到控制台。
  • std::cin用于从控制台输入数据。

示例代码:

#include <iostream>

int main() {
    int age;
    std::cout << "Enter your age: ";
    std::cin >> age;
    std::cout << "You are " << age << " years old." << std::endl;
    return 0;
}
2.2.4 基本运算符与表达式
  • 算术运算符:+-*/%
  • 比较运算符:==!=><>=<=
  • 逻辑运算符:&&||!

示例代码:

#include <iostream>

int main() {
    int a = 5, b = 3;
    std::cout << "Sum: " << (a + b) << std::endl;
    std::cout << "Comparison (a > b): " << (a > b) << std::endl;
    return 0;
}
2.2.5 条件语句

C++中的条件语句用于根据条件的真假执行不同的代码。常用的条件语句有ifelse ifelse以及switch

  • if-else语句:根据布尔表达式的值决定执行哪段代码。
  • switch语句:用于对一个表达式的值进行多重判断。

示例代码:

#include <iostream>

int main() {
    int score;
    std::cout << "Enter your score: ";
    std::cin >> score;

    if (score >= 90) {
        std::cout << "Grade: A" << std::endl;
    } else if (score >= 80) {
        std::cout << "Grade: B" << std::endl;
    } else if (score >= 70) {
        std::cout << "Grade: C" << std::endl;
    } else {
        std::cout << "Grade: F" << std::endl;
    }

    return 0;
}

2.3 实验任务:编写一个简单的计算器

在本节的实验任务中,学生将编写一个简单的控制台计算器,用户可以输入两个整数和一个运算符,程序将计算并输出结果。

实验步骤:
  1. 创建一个新的C++文件calculator.cpp
  2. 实现以下功能:
    • 用户输入两个整数和一个运算符(+-*/)。
    • 程序根据用户输入的运算符执行相应的运算,并输出结果。
    • 如果输入无效,程序应提示用户重新输入。

示例代码:

#include <iostream>

int main() {
    int num1, num2;
    char op;

    std::cout << "Enter first number: ";
    std::cin >> num1;

    std::cout << "Enter operator (+, -, *, /): ";
    std::cin >> op;

    std::cout << "Enter second number: ";
    std::cin >> num2;

    switch (op) {
        case '+':
            std::cout << "Result: " << (num1 + num2) << std::endl;
            break;
        case '-':
            std::cout << "Result: " << (num1 - num2) << std::endl;
            break;
        case '*':
            std::cout << "Result: " << (num1 * num2) << std::endl;
            break;
        case '/':
            if (num2 != 0) {
                std::cout << "Result: " << (num1 / num2) << std::endl;
            } else {
                std::cout << "Error: Division by zero!" << std::endl;
            }
            break;
        default:
            std::cout << "Invalid operator!" << std::endl;
    }

    return 0;
}

2.4 小结

本节课通过基础的C++语法讲解,帮助学生了解了如何使用变量、运算符、输入输出以及条件语句来编写简单的C++程序。通过实验任务,学生学会了结合多个C++基础语法,开发一个简单的控制台应用程序。

第3节:循环与数组

3.1 目标

本节课将学习C++中的循环结构和数组的基本用法。学生将了解如何通过循环实现重复操作,并使用数组存储和处理多个数据。通过本节的实验任务,学生将应用这些概念实现简单的算法。

3.2 基本概念

3.2.1 循环结构

C++支持三种主要的循环结构:for循环、while循环、do-while循环。

  • for循环:通常用于已知循环次数的情况。

    语法:

    for (初始化; 条件; 更新) {
        // 循环体
    }
    

    示例代码:

    for (int i = 0; i < 5; i++) {
        std::cout << "Iteration " << i << std::endl;
    }
    
  • while循环:用于在条件为真时反复执行的场合,通常适用于条件未知或动态变化的情况。

    语法:

    while (条件) {
        // 循环体
    }
    

    示例代码:

    int i = 0;
    while (i < 5) {
        std::cout << "Iteration " << i << std::endl;
        i++;
    }
    
  • do-while循环:与while循环类似,但保证循环体至少执行一次。

    语法:

    do {
        // 循环体
    } while (条件);
    

    示例代码:

    int i = 0;
    do {
        std::cout << "Iteration " << i << std::endl;
        i++;
    } while (i < 5);
    
3.2.2 数组
  • 数组:用于存储相同类型的多个数据。数组的大小在声明时确定,并且数组的元素通过下标进行访问(从0开始)。

    语法:

    数据类型 数组名[大小];
    

    示例代码:

    int numbers[5] = {10, 20, 30, 40, 50};
    for (int i = 0; i < 5; i++) {
        std::cout << "Element at index " << i << " is " << numbers[i] << std::endl;
    }
    
3.2.3 多维数组
  • 多维数组:用于表示二维或更高维度的数据,例如矩阵。

    语法:

    数据类型 数组名[行][列];
    

    示例代码:

    int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 3; j++) {
            std::cout << matrix[i][j] << " ";
        }
        std::cout << std::endl;
    }
    

3.3 基础算法练习

3.3.1 查找
  • 线性查找:遍历数组查找特定元素,返回其下标。

    示例代码:

    int numbers[] = {10, 20, 30, 40, 50};
    int target = 30;
    int index = -1;
    for (int i = 0; i < 5; i++) {
        if (numbers[i] == target) {
            index = i;
            break;
        }
    }
    if (index != -1) {
        std::cout << "Element found at index " << index << std::endl;
    } else {
        std::cout << "Element not found" << std::endl;
    }
    
3.3.2 排序(冒泡排序)
  • 冒泡排序:一种简单的排序算法,重复遍历数组并交换相邻的元素,直到整个数组有序。

    示例代码:

    int numbers[] = {50, 30, 20, 40, 10};
    int n = 5;
    for (int i = 0; i < n-1; i++) {
        for (int j = 0; j < n-i-1; j++) {
            if (numbers[j] > numbers[j+1]) {
                // 交换
                int temp = numbers[j];
                numbers[j] = numbers[j+1];
                numbers[j+1] = temp;
            }
        }
    }
    
    std::cout << "Sorted array: ";
    for (int i = 0; i < n; i++) {
        std::cout << numbers[i] << " ";
    }
    std::cout << std::endl;
    

3.4 实验任务:学生成绩管理程序

本节实验任务是编写一个简单的学生成绩管理程序,允许用户输入多个学生的成绩,并根据成绩进行统计和排序。要求学生应用循环、数组和基础算法。

实验步骤:
  1. 创建一个新的C++文件grades.cpp
  2. 程序要求:
    • 用户输入学生的数量,然后输入每个学生的成绩。
    • 计算成绩的平均值。
    • 输出最高分和最低分。
    • 使用冒泡排序对成绩从高到低排序,并输出排序结果。

示例代码:

#include <iostream>

int main() {
    int num_students;
    std::cout << "Enter the number of students: ";
    std::cin >> num_students;

    int grades[num_students];
    std::cout << "Enter the grades:" << std::endl;
    for (int i = 0; i < num_students; i++) {
        std::cin >> grades[i];
    }

    // 计算平均值
    int sum = 0;
    for (int i = 0; i < num_students; i++) {
        sum += grades[i];
    }
    double average = static_cast<double>(sum) / num_students;
    std::cout << "Average grade: " << average << std::endl;

    // 查找最高分和最低分
    int max_grade = grades[0];
    int min_grade = grades[0];
    for (int i = 1; i < num_students; i++) {
        if (grades[i] > max_grade) {
            max_grade = grades[i];
        }
        if (grades[i] < min_grade) {
            min_grade = grades[i];
        }
    }
    std::cout << "Highest grade: " << max_grade << std::endl;
    std::cout << "Lowest grade: " << min_grade << std::endl;

    // 冒泡排序
    for (int i = 0; i < num_students-1; i++) {
        for (int j = 0; j < num_students-i-1; j++) {
            if (grades[j] < grades[j+1]) {
                int temp = grades[j];
                grades[j] = grades[j+1];
                grades[j+1] = temp;
            }
        }
    }

    // 输出排序结果
    std::cout << "Grades sorted from highest to lowest:" << std::endl;
    for (int i = 0; i < num_students; i++) {
        std::cout << grades[i] << " ";
    }
    std::cout << std::endl;

    return 0;
}

3.5 小结

本节课通过讲解循环结构和数组的使用,帮助学生掌握了处理重复操作和存储多个数据的基础技能。同时,通过基础算法的应用,学生进一步理解了如何用C++编写有效的程序。在实验任务中,学生结合所学内容实现了一个简单的成绩管理程序。

第4节:函数与作用域

4.1 目标

本节课的重点是学习如何定义和使用函数。通过函数的学习,学生将掌握如何将程序逻辑进行模块化,提高代码的可读性和复用性。此外,学生还会了解变量的作用域和生命周期。

4.2 基本概念

4.2.1 函数的定义与调用

函数是一个包含特定任务的代码块,可以通过调用来执行函数中的代码。函数的定义通常包括返回类型、函数名、参数列表和函数体。

语法:

返回类型 函数名(参数类型 参数名, ...) {
    // 函数体
    return 返回值;
}

示例代码:

#include <iostream>

// 函数定义
int add(int a, int b) {
    return a + b;
}

int main() {
    int result = add(5, 3); // 函数调用
    std::cout << "Sum: " << result << std::endl;
    return 0;
}
4.2.2 函数的参数传递
  • 值传递:函数接收到的是参数的副本,对副本的修改不会影响原始变量。
  • 引用传递:通过引用传递参数,函数可以直接修改原始变量的值。

示例代码(引用传递):

#include <iostream>

// 函数定义,使用引用传递
void swap(int &a, int &b) {
    int temp = a;
    a = b;
    b = temp;
}

int main() {
    int x = 5, y = 10;
    std::cout << "Before swap: x = " << x << ", y = " << y << std::endl;
    swap(x, y);
    std::cout << "After swap: x = " << x << ", y = " << y << std::endl;
    return 0;
}
4.2.3 函数的返回值

函数可以返回任意数据类型,也可以通过void定义不返回任何值的函数。

示例代码(返回值):

#include <iostream>

// 返回最大值的函数
int max(int a, int b) {
    return (a > b) ? a : b;
}

int main() {
    int result = max(10, 20);
    std::cout << "Max: " << result << std::endl;
    return 0;
}
4.2.4 函数重载

函数重载允许多个同名函数存在,只要它们的参数类型或数量不同即可。编译器会根据函数调用时的参数类型来确定调用哪个重载函数。

示例代码:

#include <iostream>

// 重载函数
int add(int a, int b) {
    return a + b;
}

double add(double a, double b) {
    return a + b;
}

int main() {
    std::cout << "Int sum: " << add(3, 4) << std::endl;
    std::cout << "Double sum: " << add(3.5, 4.5) << std::endl;
    return 0;
}
4.2.5 递归函数

递归函数是指在函数的定义中调用该函数本身。递归在处理某些问题时非常有用,例如计算阶乘或解决分治问题。

示例代码(递归计算阶乘):

#include <iostream>

// 递归函数定义
int factorial(int n) {
    if (n <= 1) {
        return 1;
    }
    return n * factorial(n - 1);
}

int main() {
    int result = factorial(5);
    std::cout << "Factorial of 5: " << result << std::endl;
    return 0;
}
4.2.6 变量的作用域与生命周期
  • 局部变量:声明在函数内部的变量,其作用域仅限于该函数。
  • 全局变量:声明在所有函数之外的变量,作用域为整个程序。
  • 静态变量:在函数中声明为static的变量,其生命周期在整个程序运行期间保持有效,但其作用域仍然是函数内部。

示例代码(局部与全局变量):

#include <iostream>

int globalVar = 10; // 全局变量

void showVar() {
    int localVar = 5; // 局部变量
    std::cout << "Local variable: " << localVar << std::endl;
    std::cout << "Global variable: " << globalVar << std::endl;
}

int main() {
    showVar();
    std::cout << "Global variable in main: " << globalVar << std::endl;
    return 0;
}

4.3 函数与模块化编程

函数是模块化编程的重要组成部分,它能够帮助开发者将复杂的程序拆分为多个独立的功能模块。通过合理的函数划分,代码的可读性和复用性将大大提高。

4.4 实验任务:编写一个计算几何图形面积的程序

本节的实验任务是编写一个程序,计算矩形、三角形和圆形的面积。要求学生使用函数实现每种图形的面积计算,并通过函数调用来获取不同图形的面积。

实验步骤:
  1. 创建一个新的C++文件geometry.cpp
  2. 实现以下功能:
    • 编写三个函数,分别计算矩形、三角形和圆形的面积。
    • 用户可以选择计算哪种图形的面积。
    • 根据用户输入的图形参数,调用相应的函数并输出结果。

示例代码:

#include <iostream>
#include <cmath>

// 计算矩形面积的函数
double rectangleArea(double length, double width) {
    return length * width;
}

// 计算三角形面积的函数
double triangleArea(double base, double height) {
    return 0.5 * base * height;
}

// 计算圆形面积的函数
double circleArea(double radius) {
    return M_PI * radius * radius;
}

int main() {
    int choice;
    std::cout << "Choose a shape to calculate the area:" << std::endl;
    std::cout << "1. Rectangle" << std::endl;
    std::cout << "2. Triangle" << std::endl;
    std::cout << "3. Circle" << std::endl;
    std::cin >> choice;

    switch (choice) {
        case 1: {
            double length, width;
            std::cout << "Enter length and width: ";
            std::cin >> length >> width;
            std::cout << "Rectangle area: " << rectangleArea(length, width) << std::endl;
            break;
        }
        case 2: {
            double base, height;
            std::cout << "Enter base and height: ";
            std::cin >> base >> height;
            std::cout << "Triangle area: " << triangleArea(base, height) << std::endl;
            break;
        }
        case 3: {
            double radius;
            std::cout << "Enter radius: ";
            std::cin >> radius;
            std::cout << "Circle area: " << circleArea(radius) << std::endl;
            break;
        }
        default:
            std::cout << "Invalid choice!" << std::endl;
    }

    return 0;
}

4.5 小结

本节课通过学习函数的定义、调用、参数传递、递归与重载等概念,学生能够编写结构化的C++程序。结合变量的作用域和生命周期的知识,学生可以更好地理解程序的运行过程。本节的实验任务通过计算几何图形面积,帮助学生加深了对函数的实际应用。

第5节:指针与动态内存管理

5.1 目标

本节课将深入学习C++中的指针与动态内存管理。学生将了解指针的概念及其与内存地址的关系,学习如何通过指针访问和操作内存。此外,还会介绍如何使用newdelete动态管理内存,以便在程序中灵活处理内存需求。

5.2 基本概念

5.2.1 指针的概念

指针是保存内存地址的变量。通过指针,程序可以直接访问和修改存储在该地址上的数据。

语法:

数据类型* 指针名;

示例代码:

#include <iostream>

int main() {
    int a = 10;
    int* ptr = &a; // 指针保存变量a的地址

    std::cout << "Value of a: " << a << std::endl;
    std::cout << "Address of a: " << &a << std::endl;
    std::cout << "Pointer value (address of a): " << ptr << std::endl;
    std::cout << "Dereferenced pointer (value of a): " << *ptr << std::endl;

    return 0;
}
5.2.2 指针的基本操作
  • 取地址运算符&:用于获取变量的内存地址。
  • 解引用运算符*:用于通过指针访问存储在该地址上的数据。

示例代码:

#include <iostream>

int main() {
    int x = 42;
    int* ptr = &x;  // 获取x的地址

    std::cout << "Value of x: " << x << std::endl;
    *ptr = 100;  // 通过指针修改x的值
    std::cout << "New value of x: " << x << std::endl;

    return 0;
}
5.2.3 指针与数组

在C++中,数组名本身就是一个指向数组第一个元素的指针。通过指针可以遍历数组。

示例代码:

#include <iostream>

int main() {
    int arr[3] = {10, 20, 30};
    int* ptr = arr;  // 数组名即指向第一个元素的指针

    for (int i = 0; i < 3; i++) {
        std::cout << "arr[" << i << "] = " << *(ptr + i) << std::endl;  // 通过指针访问数组元素
    }

    return 0;
}
5.2.4 动态内存分配
  • new运算符:用于动态分配内存,返回指向分配内存的指针。
  • delete运算符:用于释放动态分配的内存,防止内存泄漏。

示例代码(动态分配单个变量):

#include <iostream>

int main() {
    int* ptr = new int;  // 动态分配一个整数
    *ptr = 42;

    std::cout << "Dynamically allocated value: " << *ptr << std::endl;
    delete ptr;  // 释放动态分配的内存

    return 0;
}

示例代码(动态分配数组):

#include <iostream>

int main() {
    int* arr = new int[5];  // 动态分配一个数组

    for (int i = 0; i < 5; i++) {
        arr[i] = i * 10;
    }

    std::cout << "Dynamically allocated array:" << std::endl;
    for (int i = 0; i < 5; i++) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;

    delete[] arr;  // 释放动态分配的数组内存

    return 0;
}
5.2.5 空指针与指针检查
  • 空指针(nullptr:用于表示指针不指向任何有效内存地址。
  • 指针检查:在使用指针之前,应确保指针不为空。

示例代码:

#include <iostream>

int main() {
    int* ptr = nullptr;  // 空指针

    if (ptr == nullptr) {
        std::cout << "Pointer is null." << std::endl;
    }

    return 0;
}
5.2.6 常见的指针错误
  • 悬空指针:指向已被释放或无效的内存。
  • 野指针:未被初始化的指针。
  • 内存泄漏:动态分配的内存未被释放。

5.3 实验任务:学生成绩的动态存储

本节的实验任务是编写一个程序,允许用户动态输入学生成绩,并存储这些成绩以便后续处理。要求学生使用指针和动态内存管理实现。

实验步骤:
  1. 创建一个新的C++文件dynamic_grades.cpp
  2. 实现以下功能:
    • 用户输入学生人数,动态分配内存以存储学生的成绩。
    • 用户输入每个学生的成绩。
    • 计算并输出成绩的平均值。
    • 释放动态分配的内存。

示例代码:

#include <iostream>

int main() {
    int num_students;
    std::cout << "Enter the number of students: ";
    std::cin >> num_students;

    // 动态分配用于存储学生成绩的内存
    int* grades = new int[num_students];

    // 输入每个学生的成绩
    std::cout << "Enter the grades:" << std::endl;
    for (int i = 0; i < num_students; i++) {
        std::cin >> grades[i];
    }

    // 计算平均成绩
    int sum = 0;
    for (int i = 0; i < num_students; i++) {
        sum += grades[i];
    }
    double average = static_cast<double>(sum) / num_students;
    std::cout << "Average grade: " << average << std::endl;

    // 释放动态分配的内存
    delete[] grades;

    return 0;
}

5.4 深入理解:指针与函数

指针可以作为函数的参数传递,用于在函数中修改实参的值或访问动态分配的内存。指针也可以用来返回动态分配的内存地址。

示例代码(指针作为参数):

#include <iostream>

// 使用指针交换两个整数的值
void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int x = 10, y = 20;
    std::cout << "Before swap: x = " << x << ", y = " << y << std::endl;

    swap(&x, &y);  // 传递变量的地址
    std::cout << "After swap: x = " << x << ", y = " << y << std::endl;

    return 0;
}

5.5 小结

本节课通过指针和动态内存管理的学习,学生能够理解内存的操作原理,并掌握动态分配和释放内存的方法。通过实验任务,学生实践了如何灵活处理数据的存储与管理。掌握指针是C++编程的重要基础,在后续的C++高级编程中,指针的概念将会更加广泛地应用。

第6节:面向对象编程基础

6.1 目标

本节课将介绍C++中的面向对象编程(OOP)概念,帮助学生理解类与对象的基本原理。通过学习类的定义、对象的创建与使用、构造函数与析构函数、成员函数与成员变量等内容,学生将掌握如何使用OOP思想来设计和实现程序。

6.2 基本概念

6.2.1 类与对象

类是面向对象编程中的核心概念,它是数据和方法的封装体。对象是类的实例,具有类中定义的属性和行为。

类的定义语法:

class 类名 {
public:
    // 公共成员变量和成员函数
    数据类型 变量名;
    返回类型 函数名(参数);
};

示例代码:

#include <iostream>

class Person {
public:
    // 成员变量
    std::string name;
    int age;

    // 成员函数
    void introduce() {
        std::cout << "Hi, my name is " << name << " and I am " << age << " years old." << std::endl;
    }
};

int main() {
    // 创建对象
    Person person;
    person.name = "Alice";
    person.age = 25;
    person.introduce();

    return 0;
}
6.2.2 构造函数与析构函数
  • 构造函数:用于在创建对象时初始化对象的状态。构造函数与类同名,没有返回类型。
  • 析构函数:用于在对象销毁时执行清理工作,析构函数的名字在类名前加~,同样没有返回类型。

示例代码:

#include <iostream>

class Person {
public:
    std::string name;
    int age;

    // 构造函数
    Person(std::string n, int a) : name(n), age(a) {
        std::cout << "Person object created!" << std::endl;
    }

    // 析构函数
    ~Person() {
        std::cout << "Person object destroyed!" << std::endl;
    }

    void introduce() {
        std::cout << "Hi, my name is " << name << " and I am " << age << " years old." << std::endl;
    }
};

int main() {
    // 使用构造函数创建对象
    Person person("Bob", 30);
    person.introduce(); // 输出介绍信息

    return 0;
}
6.2.3 访问控制(public、private、protected)
  • public:公共成员可以在类的外部访问。
  • private:私有成员只能在类的内部访问。
  • protected:受保护的成员只能在类内部或派生类中访问。

示例代码:

#include <iostream>

class Person {
private:
    std::string name;
    int age;

public:
    // 公共成员函数用于访问私有成员
    void setDetails(std::string n, int a) {
        name = n;
        age = a;
    }

    void introduce() {
        std::cout << "Hi, my name is " << name << " and I am " << age << " years old." << std::endl;
    }
};

int main() {
    Person person;
    person.setDetails("Charlie", 28);
    person.introduce();

    return 0;
}
6.2.4 成员函数与成员变量

成员函数是类内部定义的函数,用于操作成员变量。成员变量存储对象的状态,成员函数则定义对象的行为。

示例代码:

#include <iostream>

class Circle {
public:
    double radius;

    // 成员函数:计算圆的面积
    double getArea() {
        return 3.14159 * radius * radius;
    }
};

int main() {
    Circle circle;
    circle.radius = 5.0;
    std::cout << "Circle area: " << circle.getArea() << std::endl;

    return 0;
}

6.3 深入理解类与对象

6.3.1 this指针

this指针是类中隐含的指针,它指向当前对象,可以用来区分成员变量与函数参数重名的情况。

示例代码:

#include <iostream>

class Rectangle {
private:
    int width, height;

public:
    // 使用this指针来区分成员变量和参数
    void setDimensions(int width, int height) {
        this->width = width;
        this->height = height;
    }

    int getArea() {
        return width * height;
    }
};

int main() {
    Rectangle rect;
    rect.setDimensions(5, 10);
    std::cout << "Rectangle area: " << rect.getArea() << std::endl;

    return 0;
}
6.3.2 静态成员变量与静态成员函数

静态成员变量属于类,而不属于某个特定对象。所有对象共享静态成员变量。静态成员函数可以直接访问静态成员变量。

示例代码:

#include <iostream>

class Counter {
public:
    static int count;

    Counter() {
        count++;
    }

    static void showCount() {
        std::cout << "Count: " << count << std::endl;
    }
};

// 初始化静态成员变量
int Counter::count = 0;

int main() {
    Counter c1, c2, c3;
    Counter::showCount();  // 调用静态成员函数

    return 0;
}

6.4 实验任务:学生信息管理系统

本节的实验任务是设计一个简单的学生信息管理系统,使用面向对象的方式存储和管理学生的信息。要求实现以下功能:

  • 定义一个Student类,包含学生的姓名、年龄和成绩等属性。
  • 提供构造函数和成员函数用于操作学生数据。
  • 创建多个Student对象,并展示每个学生的信息。
实验步骤:
  1. 创建一个新的C++文件student_system.cpp
  2. 实现以下功能:
    • 定义Student类,包含姓名、年龄和成绩等私有成员。
    • 编写构造函数和introduce函数,用于输出学生信息。
    • main函数中创建并初始化多个学生对象,调用相关函数输出学生信息。

示例代码:

#include <iostream>

class Student {
private:
    std::string name;
    int age;
    double grade;

public:
    // 构造函数
    Student(std::string n, int a, double g) : name(n), age(a), grade(g) {}

    // 输出学生信息
    void introduce() {
        std::cout << "Student: " << name << ", Age: " << age << ", Grade: " << grade << std::endl;
    }
};

int main() {
    // 创建学生对象
    Student student1("Alice", 20, 88.5);
    Student student2("Bob", 19, 91.2);

    // 输出学生信息
    student1.introduce();
    student2.introduce();

    return 0;
}

6.5 小结

本节课学生学习了面向对象编程的基础知识,包括类的定义、对象的创建、构造函数与析构函数、成员函数与成员变量、访问控制以及静态成员等概念。通过实验任务,学生加深了对OOP思想的理解,能够运用OOP方法进行程序设计。面向对象编程是C++中的核心思想,将在后续的课程中进一步扩展。

第7节:继承与多态

7.1 目标

本节课将介绍面向对象编程中的两个重要特性:继承与多态。继承允许一个类从另一个类继承属性和方法,复用代码并扩展功能;多态则使得不同类型的对象可以通过统一的接口进行操作,从而提高代码的灵活性。学生将学习如何定义基类和派生类,以及如何使用虚函数实现多态。

7.2 基本概念

7.2.1 继承

继承是从已有的类(基类或父类)创建新类(派生类或子类)的机制。派生类继承了基类的成员变量和成员函数,可以复用基类的代码并添加新的功能。

继承语法:

class 派生类名 : 访问修饰符 基类名 {
public:
    // 派生类中的新成员变量和成员函数
};

示例代码:

#include <iostream>

class Animal {
public:
    void eat() {
        std::cout << "This animal is eating." << std::endl;
    }
};

// Dog类继承自Animal类
class Dog : public Animal {
public:
    void bark() {
        std::cout << "The dog is barking." << std::endl;
    }
};

int main() {
    Dog dog;
    dog.eat();  // 调用基类的函数
    dog.bark(); // 调用派生类的函数

    return 0;
}
7.2.2 访问修饰符在继承中的作用

继承时,可以通过访问修饰符控制基类成员在派生类中的可见性:

  • public继承:基类的public成员在派生类中保持为publicprotected成员保持为protectedprivate成员不可访问。
  • protected继承:基类的publicprotected成员在派生类中变为protectedprivate成员不可访问。
  • private继承:基类的所有非私有成员在派生类中变为private

示例代码:

#include <iostream>

class Base {
public:
    int x = 10;

protected:
    int y = 20;

private:
    int z = 30;
};

// 派生类继承自Base类
class Derived : public Base {
public:
    void show() {
        std::cout << "x = " << x << std::endl;  // 可以访问public成员
        std::cout << "y = " << y << std::endl;  // 可以访问protected成员
        // std::cout << "z = " << z << std::endl;  // 无法访问private成员
    }
};

int main() {
    Derived d;
    d.show();
    return 0;
}
7.2.3 构造函数与析构函数在继承中的调用顺序

在继承结构中,基类的构造函数在派生类的构造函数之前调用,析构函数则按相反的顺序执行,即先调用派生类的析构函数,再调用基类的析构函数。

示例代码:

#include <iostream>

class Base {
public:
    Base() {
        std::cout << "Base constructor called." << std::endl;
    }

    ~Base() {
        std::cout << "Base destructor called." << std::endl;
    }
};

class Derived : public Base {
public:
    Derived() {
        std::cout << "Derived constructor called." << std::endl;
    }

    ~Derived() {
        std::cout << "Derived destructor called." << std::endl;
    }
};

int main() {
    Derived d;
    return 0;
}

7.3 多态

7.3.1 虚函数与动态绑定

多态允许使用基类的指针或引用操作派生类对象,从而实现灵活的运行时行为。要实现多态,必须使用虚函数(virtual function)。通过将基类中的函数声明为虚函数,可以确保派生类覆盖该函数时,在运行时调用的是派生类的实现,而不是基类的实现。

示例代码:

#include <iostream>

class Animal {
public:
    // 基类中的虚函数
    virtual void sound() {
        std::cout << "This animal makes a sound." << std::endl;
    }
};

class Dog : public Animal {
public:
    // 覆盖基类的虚函数
    void sound() override {
        std::cout << "The dog barks." << std::endl;
    }
};

class Cat : public Animal {
public:
    // 覆盖基类的虚函数
    void sound() override {
        std::cout << "The cat meows." << std::endl;
    }
};

int main() {
    Animal* animal;
    Dog dog;
    Cat cat;

    // 基类指针指向派生类对象
    animal = &dog;
    animal->sound();  // 调用Dog类的sound()函数

    animal = &cat;
    animal->sound();  // 调用Cat类的sound()函数

    return 0;
}
7.3.2 纯虚函数与抽象类

如果基类中的某个虚函数没有具体实现,可以将其声明为纯虚函数,使得该类成为抽象类,不能实例化。派生类必须实现所有纯虚函数,才能创建对象。

语法:

virtual 返回类型 函数名(参数) = 0;

示例代码:

#include <iostream>

// 抽象类Shape
class Shape {
public:
    // 纯虚函数
    virtual void draw() = 0;
};

class Circle : public Shape {
public:
    // 实现纯虚函数
    void draw() override {
        std::cout << "Drawing a circle." << std::endl;
    }
};

class Square : public Shape {
public:
    // 实现纯虚函数
    void draw() override {
        std::cout << "Drawing a square." << std::endl;
    }
};

int main() {
    Shape* shape;
    Circle circle;
    Square square;

    shape = &circle;
    shape->draw();  // 调用Circle的draw()函数

    shape = &square;
    shape->draw();  // 调用Square的draw()函数

    return 0;
}

7.4 实验任务:多态的形状绘制系统

本节的实验任务是设计一个多态的形状绘制系统,要求定义一个抽象类Shape,并由CircleSquareTriangle类继承。每个派生类实现draw()函数,输出对应形状的绘制信息。要求使用多态机制,通过基类指针或引用操作派生类对象。

实验步骤:
  1. 创建一个新的C++文件shape_system.cpp
  2. 实现以下功能:
    • 定义Shape抽象类,包含纯虚函数draw()
    • CircleSquareTriangle类继承Shape并实现draw()函数。
    • main函数中,创建一个Shape指针数组,依次存放不同形状对象,通过多态调用draw()函数。

示例代码:

#include <iostream>

// 抽象类Shape
class Shape {
public:
    virtual void draw() = 0;  // 纯虚函数
};

class Circle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a circle." << std::endl;
    }
};

class Square : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a square." << std::endl;
    }
};

class Triangle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a triangle." << std::endl;
    }
};

int main() {
    // 创建形状对象的指针数组
    Shape* shapes[3];
    shapes[0] = new Circle();
    shapes[1] = new Square();
    shapes[2] = new Triangle();

    // 使用多态调用draw()函数
    for (int i = 0; i < 3; i++) {
        shapes[i]->draw();
    }

    // 释放内存
    for (int i = 0; i < 3; i++) {
        delete shapes[i];
    }

    return 0;
}

7.5 小结

本节课学生学习了继承和多态的概念与应用,继承帮助代码复用和扩展,虚函数与多态提供了灵活的运行时行为。通过实验任务,学生能够理解如何设计和实现支持多态的类层次结构,进一步掌握面向对象编程的核心思想。

第8节:智能指针与C++内存管理

8.1 目标

本节课的目标是帮助学生理解C++中的内存管理,包括动态内存分配和释放。为了更好地管理内存并避免内存泄漏,C++11引入了智能指针(smart pointers),如std::unique_ptrstd::shared_ptrstd::weak_ptr。本节将学习如何使用这些智能指针来管理动态内存,并探讨它们的适用场景。

8.2 动态内存管理

8.2.1 动态内存分配与释放

在C++中,可以使用new关键字动态分配内存,用delete关键字释放内存。动态分配的内存不会自动释放,需要手动调用delete,否则会产生内存泄漏

示例代码:

#include <iostream>

int main() {
    // 动态分配一个int变量
    int* p = new int(10);
    std::cout << "Value: " << *p << std::endl;

    // 手动释放内存
    delete p;

    return 0;
}
8.2.2 动态分配数组

动态分配数组时,使用new[]分配内存,使用delete[]释放内存。

示例代码:

#include <iostream>

int main() {
    // 动态分配一个数组
    int* arr = new int[5];
    
    for (int i = 0; i < 5; i++) {
        arr[i] = i * 10;
    }

    for (int i = 0; i < 5; i++) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;

    // 释放数组内存
    delete[] arr;

    return 0;
}

8.3 智能指针

C++11引入了智能指针,用于自动管理动态内存,避免内存泄漏。智能指针是模板类,负责在对象不再使用时自动释放其占用的内存。

8.3.1 std::unique_ptr

std::unique_ptr是一种独占型智能指针,确保同一时刻只有一个指针指向某个对象。不能复制unique_ptr,只能通过转移所有权(使用std::move)来共享对象的控制权。

使用场景:适合对象的独占所有权场景,如RAII(资源获取即初始化)模式。

示例代码:

#include <iostream>
#include <memory>  // 包含智能指针库

class Resource {
public:
    Resource() {
        std::cout << "Resource acquired." << std::endl;
    }
    ~Resource() {
        std::cout << "Resource released." << std::endl;
    }
};

int main() {
    std::unique_ptr<Resource> res1 = std::make_unique<Resource>();  // 自动管理内存
    // std::unique_ptr<Resource> res2 = res1;  // 错误,不能复制unique_ptr

    std::unique_ptr<Resource> res2 = std::move(res1);  // 转移所有权
    if (!res1) {
        std::cout << "res1 no longer owns the resource." << std::endl;
    }

    return 0;
}
8.3.2 std::shared_ptr

std::shared_ptr是一种共享所有权的智能指针,允许多个指针同时指向同一个对象。它使用引用计数来跟踪有多少指针指向该对象,当最后一个指针被销毁时,自动释放对象的内存。

使用场景:适合多个对象共享资源的场景,如缓存或共享数据。

示例代码:

#include <iostream>
#include <memory>

class Resource {
public:
    Resource() {
        std::cout << "Resource acquired." << std::endl;
    }
    ~Resource() {
        std::cout << "Resource released." << std::endl;
    }
};

int main() {
    std::shared_ptr<Resource> res1 = std::make_shared<Resource>();
    std::cout << "Reference count: " << res1.use_count() << std::endl;

    {
        std::shared_ptr<Resource> res2 = res1;  // 共享所有权
        std::cout << "Reference count: " << res1.use_count() << std::endl;
    }  // res2销毁,但资源不会释放,因为res1还在使用

    std::cout << "Reference count: " << res1.use_count() << std::endl;

    return 0;
}
8.3.3 std::weak_ptr

std::weak_ptr是一种弱引用,不增加对象的引用计数。它通常与std::shared_ptr配合使用,解决循环引用的问题。weak_ptr不能直接访问对象,需要先通过lock()方法转换为shared_ptr

使用场景:适合防止循环引用的场景,如观察者模式或双向关联。

示例代码:

#include <iostream>
#include <memory>

class Resource {
public:
    Resource() {
        std::cout << "Resource acquired." << std::endl;
    }
    ~Resource() {
        std::cout << "Resource released." << std::endl;
    }
};

int main() {
    std::shared_ptr<Resource> res1 = std::make_shared<Resource>();
    std::weak_ptr<Resource> weakRes = res1;  // 创建一个弱引用

    if (auto tempRes = weakRes.lock()) {  // 检查对象是否仍然存在
        std::cout << "Resource is still alive." << std::endl;
    } else {
        std::cout << "Resource has been released." << std::endl;
    }

    return 0;
}

8.4 实验任务:内存管理与智能指针

本节的实验任务是设计一个简单的内存管理系统,使用智能指针来管理动态分配的资源。任务要求包括:

  • 使用std::unique_ptr管理独占资源。
  • 使用std::shared_ptr管理共享资源,并显示引用计数。
  • 使用std::weak_ptr避免循环引用。
实验步骤:
  1. 创建一个新的C++文件smart_pointer_demo.cpp
  2. 实现以下功能:
    • 使用std::unique_ptr创建独占资源并转移所有权。
    • 使用std::shared_ptr管理共享资源,并在不同作用域中显示引用计数。
    • 使用std::weak_ptr防止循环引用。

示例代码:

#include <iostream>
#include <memory>

class Resource {
public:
    Resource() {
        std::cout << "Resource acquired." << std::endl;
    }
    ~Resource() {
        std::cout << "Resource released." << std::endl;
    }
};

void uniquePointerDemo() {
    std::unique_ptr<Resource> res1 = std::make_unique<Resource>();
    std::unique_ptr<Resource> res2 = std::move(res1);
    if (!res1) {
        std::cout << "Unique pointer transferred ownership." << std::endl;
    }
}

void sharedPointerDemo() {
    std::shared_ptr<Resource> res1 = std::make_shared<Resource>();
    std::cout << "Initial reference count: " << res1.use_count() << std::endl;

    {
        std::shared_ptr<Resource> res2 = res1;
        std::cout << "Reference count in scope: " << res1.use_count() << std::endl;
    }

    std::cout << "Reference count after scope: " << res1.use_count() << std::endl;
}

void weakPointerDemo() {
    std::shared_ptr<Resource> res1 = std::make_shared<Resource>();
    std::weak_ptr<Resource> weakRes = res1;

    if (auto tempRes = weakRes.lock()) {
        std::cout << "Resource is still alive." << std::endl;
    } else {
        std::cout << "Resource has been released." << std::endl;
    }
}

int main() {
    std::cout << "Unique Pointer Demo:" << std::endl;
    uniquePointerDemo();

    std::cout << "\nShared Pointer Demo:" << std::endl;
    sharedPointerDemo();

    std::cout << "\nWeak Pointer Demo:" << std::endl;
    weakPointerDemo();

    return 0;
}

8.5 小结

本节课学生学习了C++中的内存管理,理解了动态内存分配和释放的原理,并掌握了如何使用C++11引入的智能指针来避免内存泄漏。通过智能指针的自动管理功能,学生能够编写出更健壮、更安全的代码。智能指针是现代C++中非常重要的工具,它们提高了代码的可维护性并减少了内存管理的复杂性。在后续课程中,智能指针将继续用于更复杂的项目开发。

第9节:模板与泛型编程

9.1 目标

本节课的目标是帮助学生理解C++模板的基本概念以及如何进行泛型编程。模板是C++的强大特性之一,能够让代码具有更高的复用性和灵活性。通过本节的学习,学生将学会编写函数模板、类模板,并了解模板特化和变参模板等高级用法。

9.2 函数模板

9.2.1 什么是函数模板?

函数模板是一种使函数能够处理不同数据类型的工具。通过使用模板,函数可以在编译时根据传入的参数类型自动生成对应的函数代码,避免为每种类型重复编写相同的逻辑。

语法:

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

示例代码:

#include <iostream>

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

int main() {
    std::cout << "Max of 3 and 7: " << max(3, 7) << std::endl;
    std::cout << "Max of 5.6 and 3.2: " << max(5.6, 3.2) << std::endl;
    std::cout << "Max of 'a' and 'z': " << max('a', 'z') << std::endl;
    
    return 0;
}
9.2.2 使用多个模板参数

函数模板可以使用多个模板参数,使函数能够处理多种类型的组合。

示例代码:

#include <iostream>

template<typename T1, typename T2>
auto add(T1 a, T2 b) {
    return a + b;
}

int main() {
    std::cout << "Addition of 5 and 3.2: " << add(5, 3.2) << std::endl;
    
    return 0;
}

9.3 类模板

9.3.1 什么是类模板?

类模板允许定义模板类,从而创建可以处理不同数据类型的类。类模板在C++标准库(如std::vectorstd::map等容器)中大量使用。

语法:

template<typename T>
class Box {
    T value;
public:
    Box(T val) : value(val) {}
    T getValue() const { return value; }
};

示例代码:

#include <iostream>

template<typename T>
class Box {
    T value;
public:
    Box(T val) : value(val) {}
    T getValue() const { return value; }
};

int main() {
    Box<int> intBox(123);
    Box<std::string> strBox("Hello, World!");

    std::cout << "Integer Box: " << intBox.getValue() << std::endl;
    std::cout << "String Box: " << strBox.getValue() << std::endl;

    return 0;
}
9.3.2 类模板的部分特化

类模板的部分特化允许为某些特定类型或条件提供不同的实现。这在需要针对某些特殊类型优化或改变行为时非常有用。

示例代码:

#include <iostream>

template<typename T>
class Box {
    T value;
public:
    Box(T val) : value(val) {}
    T getValue() const { return value; }
};

// 对指针类型进行部分特化
template<typename T>
class Box<T*> {
    T* value;
public:
    Box(T* val) : value(val) {}
    T getValue() const { return *value; }
};

int main() {
    int num = 42;
    Box<int*> intPointerBox(&num);
    
    std::cout << "Pointer Box: " << intPointerBox.getValue() << std::endl;

    return 0;
}

9.4 变参模板

9.4.1 什么是变参模板?

变参模板(Variadic Templates)允许模板接收任意数量的参数。这使得编写更通用和灵活的模板成为可能,特别是在处理不定参数的情况下非常有用。

示例代码:

#include <iostream>

// 基础模板
template<typename T>
void print(T value) {
    std::cout << value << std::endl;
}

// 递归展开模板参数
template<typename T, typename... Args>
void print(T value, Args... args) {
    std::cout << value << ", ";
    print(args...);
}

int main() {
    print(1, 2.5, "Hello", 'A');
    return 0;
}
9.4.2 结合变参模板和折叠表达式

C++17引入了折叠表达式(Fold Expression),使得对变参模板的参数执行操作变得更加简单。

示例代码:

#include <iostream>

// 使用折叠表达式计算参数之和
template<typename... Args>
auto sum(Args... args) {
    return (args + ...);
}

int main() {
    std::cout << "Sum: " << sum(1, 2, 3, 4, 5) << std::endl;
    return 0;
}

9.5 实验任务:泛型编程

任务要求
  1. 编写一个函数模板compare,可以比较两个不同类型的值。
  2. 编写一个类模板Pair,能够存储一对不同类型的值,并实现方法first()second()分别返回第一个和第二个值。
  3. 使用变参模板编写一个printAll函数,能够接受任意数量的参数并逐个打印。
实验步骤
  1. 创建一个新的C++文件template_demo.cpp
  2. 实现函数模板compare,类模板Pair,以及变参模板函数printAll
  3. 运行程序并测试这些模板函数。

示例代码:

#include <iostream>

// 1. 函数模板 compare
template<typename T1, typename T2>
bool compare(T1 a, T2 b) {
    return a == b;
}

// 2. 类模板 Pair
template<typename T1, typename T2>
class Pair {
    T1 firstVal;
    T2 secondVal;
public:
    Pair(T1 first, T2 second) : firstVal(first), secondVal(second) {}
    T1 first() const { return firstVal; }
    T2 second() const { return secondVal; }
};

// 3. 变参模板 printAll
template<typename... Args>
void printAll(Args... args) {
    (std::cout << ... << (args << " ")) << std::endl;
}

int main() {
    // 测试 compare 函数模板
    std::cout << "Compare 10 and 10.0: " << compare(10, 10.0) << std::endl;

    // 测试类模板 Pair
    Pair<int, std::string> p(1, "Hello");
    std::cout << "Pair: " << p.first() << ", " << p.second() << std::endl;

    // 测试变参模板 printAll
    printAll(1, 2.5, "Hello", 'A');

    return 0;
}

9.6 小结

本节课学生学习了C++模板的基本概念以及如何通过泛型编程实现代码的复用和灵活性。模板使得编写通用的函数和类成为可能,而变参模板则进一步增强了模板的灵活性。在现代C++开发中,模板广泛应用于标准库和自定义容器、算法的设计。本节为后续的高级编程奠定了重要基础。

标签:std,函数,示例,int,cout,C++,入门
From: https://www.cnblogs.com/math/p/18441607/cpp

相关文章

  • 南沙C++信奥赛陈老师解一本通题:1945:【09NOIP普及组】多项式输出
    ​ 【题目描述】一元 nn 次多项式可用如下的表达式表示: f(x)=anxn+an−1xn−1+...+a1x+a0,an≠0f(x)=anxn+an−1xn−1+...+a1x+a0,an≠0 其中,aixii 称为i次项,ai称为ii次项的系数。给出一个一元多项式各项的次数和系数,请按照如下规定的格式要求输出该多项式:1.多项式中......
  • 分享C++程序员面试八股文(十四)
    以下是C++常见八股文(十四):一、C++中的智能指针高级用法(AdvancedUsageofSmartPointers)解释unique_ptr、shared_ptr和weak_ptr的循环引用问题及解决方法循环引用问题:当使用shared_ptr进行相互引用时,可能会导致循环引用问题。例如,两个对象相互持有对方的shared_pt......
  • c++:引用
    一、引用概念是什么?引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。比如:李逵,在家称为"铁牛",江湖上人称"黑旋风"类型&引用变量名(对象名)=引用实体;voidTestRef(){inta=10;int......
  • 从入门到精通,一份完整的黑客技术成长清单
    在2017年,一个名叫“AwesomeHacking”的GitHub项目曾引发大量网友的关注,这个项目是由@HackwithGithub维护的,这是一个经常会发布一些最新安全开源项目和黑客技巧的Twitter账户。“AwesomeHacking”是一份完整的黑客技术成长清单,里边索引了数十个不同方向的黑客技能图谱。如......
  • C++发邮件:如何轻松实现邮件自动化发送?
    C++发邮件的详细步骤与教程指南?如何在C++中发邮件?无论是定期发送报告、通知客户还是管理内部沟通,自动化邮件系统都能显著提升工作效率。AokSend将详细介绍如何使用C++发邮件,实现邮件自动化发送,帮助您轻松管理邮件通信。C++发邮件:配置环境在选择了合适的C++发邮件库之后,接下......
  • 南沙C++信奥赛陈老师解一本通题 1269:【例9.13】庆功会
    ​ 【题目描述】为了庆贺班级在校运动会上取得全校第一名成绩,班主任决定开一场庆功会,为此拨款购买奖品犒劳运动员。期望拨款金额能购买最大价值的奖品,可以补充他们的精力和体力。【输入】第一行二个数n(n≤500),m(m≤6000),其中n代表希望购买的奖品的种数,m表示拨款金额。接......
  • [.NET Blog] .NET Aspire 测试入门
    https://devblogs.microsoft.com/dotnet/getting-started-with-testing-and-dotnet-aspire/自动化测试是软件开发的重要一环。它可以帮助我们尽早确认软件中的缺陷和防止回归问题。在本文中,我们将探讨如何在.NETAspire中开始测试,支持我们进行跨分布式应用的测试场景。测试分......
  • 网络安全自学入门:(超详细)从入门到精通学习路线&规划,学完即可就业
    ......
  • C++ struct和class的异同、C中和C++中struct的异同
    一、前言C++中的struct结构体和C语言中的struct结构体差异较大。C++中的struct结构体和C++中的class类极为相似。二、C++的struct和class1.相同点      (1)成员     struct和class都可以在主体中定义成员变量和成员函数!两者在定义成员变量和成员函数上......
  • C++ string的基本运用详细解剖
    string的基本操作一.与C语言中字符串的区别二.标准库中的string三.string中常用接口的介绍1.string中常用的构造函数2.string类对象的容量操作函数3.string类对象的访问及遍历操作4.string类对象的修改操作5.string类的非成员函数6.string中的其他一些操作一.与C语言......