C++ 重要特性探究

news2024/9/21 12:33:58

shared_from_this

使用分析

  • 场景
    • 类的成员函数需要获取指向自身的shared_ptr的时候
    • 类成员函数传递shared_ptr给其他函数或者对象的时候,目的是为了管理对象生命周期
  • 使用方法
    • 首先类必须继承 std::enable_shared_from_this<T>
    • 必须使用 shared_from_this 获取指向自身的shared_ptr

#include<iostream>
#include<memory>

using namespace std;

class MyClass :public std::enable_shared_from_this<MyClass>
{
public:
	void show()
	{
		cout << "MyClass : show 运行" << endl;
	}
	
	//返回一个shared_ptr指向自身
	std::shared_ptr<MyClass> getSharedPtr()
	{
		return shared_from_this();
	}
	//获取shared_Ptr然后调用它
	void process()
	{
		std::shared_ptr<MyClass> ptr = shared_from_this();
		Funcaion(ptr);

	}
	void Funcaion(std::shared_ptr<MyClass>ptr)
	{
		cout << "函数内部传入的shared_ptr指针使用次数:" << ptr.use_count() << endl;
		ptr->show();
	}
};

int main()
{
	//创建一个指向Myclass的share_ptr指针
	std::shared_ptr<MyClass> obj = std::make_shared<MyClass>();

	//调用类内成员函数,获取shared_ptr自身
	std::shared_ptr<MyClass> selfptr = obj->getSharedPtr();

	//验证shared_ptr的使用次数
	cout << "shared_ptr use_count:" << selfptr.use_count() << endl;
	//cout << obj.use_count() << endl;

	//两个指针都可以调用类内成员函数验证
	obj->process();
	selfptr->process();
}

 左值和右值

左值:表达式的结果是一个持久对象,也就是该值可以取地址(内存区域是确定的)。左值通常出现在赋值操作符左侧的值

 

右值: 表达式的结果是一个临时值,不可以取地址,通常是赋值操作符右侧的数值

 

左值引用:利用&表示引用的类型,可以绑定到左值 

 

 右值引用:&&表示的引用类型,目的是操控临时对象,减少拷贝临时对象而产生性能消耗

 

移动语义:也就是不用复制对象直接将资源进行移动即可,减少性能消耗 

#include <iostream>
#include <vector>

std::vector<int> createVector() {
    std::vector<int> temp = {1, 2, 3};
    return temp; // 返回的是一个右值
}

int main() {
    std::vector<int> vec = createVector(); // 这里使用移动语义
    for(int i : vec) {
        std::cout << i << " ";
    }
    return 0;
}

左值转换成右值场景分析

  • 当左值出现在赋值运算符右侧的时候,会自动将其转化为右值
  • 当左值作为算法的数时,会自动将其转换为右值
  • 左值作为参数的时候,传递给一个按值传递的函数时候,会自动转换为右值

注意:转换过程中,左值本身是没有消失的,而是生成了一个右值,表示左值所指向的信息(后面的代码会验证)

 

#include <iostream>

int main() {
    int a = 10; // a 是一个左值
    int b = a;  // 这里发生了左值到右值的转换,a 的值(10)被赋给 b

    std::cout << "a: " << a << std::endl; // a 是左值
    std::cout << "b: " << b << std::endl; // b 是左值,打印出来的值是 10

    int* p = &a; // 获取 a 的地址
    std::cout << "Address of a: " << p << std::endl;

    return 0;
}

 引用折叠

  • 作用:复杂引用类型中,确定最终的引用类型是什么
  • 规则总结
    • T& & 变为 T&
    • T& && 变为 T&
    • T&& & 变为 T&
    • T&& && 变为 T&& (特点:只有双&&时,最终才是&&,剩下情况都是&)

事例分析(完美转发)

  •  功能:将一个参数完整的转发给另一个函数,也就是说不改变值的类型,原本是左值就还是左值,右值还是右值。(具体理解看函数实现吧)
  • 具体实现:结合引用折叠规则,必须传入左值,当T被推导的时候,就是 & &&最终得到的也就是 &

#include <iostream>
#include <utility> // for std::forward

// 接受左值引用
void process(int& x) {
    std::cout << "左值引用: " << x << std::endl;
}

// 接受右值引用
void process(int&& x) {
    std::cout << "右值引用: " << x << std::endl;
}

// 用于完美转发
template <typename T>
void forwarder(T&& arg) {
    process(std::forward<T>(arg));
}

int main() {
    int a = 10;
    forwarder(a);          // 调用 process(int&)  - 传递左值
    forwarder(20);         // 调用 process(int&&) - 传递右值
    forwarder(std::move(a)); // 调用 process(int&&) - 传递右值

    return 0;
}

 std::move

  • 使用方法
    • 将一个对象的所有权从一个地方转移到另一个地方,本质是移动而不是复制资源
  • 实现原理(结合函数原型理解)
    • 模板参数类型是&&万能引用,所以可以根据传入的参数类型,T可以是任意的成为左值引用或者右值引用
    • remove_reference是类型萃取,主要是用于去除T的引用,无论是左值引用还是右值引用最终都变成原型
    • static_cast:将参数显式的转换为右值引用,也就是说即使传递的是一个左值,move最终也会将其变成一个右值

 

 C++指针

指针和引用的区别

  • 指针是一个存储地址的变量,可以为空,同样也可以重新指向不同的对象,也可以进行指针算术运算
  • 引用则是一个对象的别名,必须在声明的时候初始化,不可以重新绑定,更不可以为空
  • 使用场景不同
    • 指针常用在需要动态分配内存或者需要表示未初始化状态的时候
    • 引用则是需要传递函数参数,避免大量复制数据,或者函数返回的时候,避免造成内存消耗

重要的区别如下

 

  • 函数指针
    • 参数说明(参考下面函数指针定义一同理解)
      • return_type:函数返回的类型
      • pointer_name:指针变量名称(可以理解为就是函数名)
      • parameter_list:函数的参数列表
    • 具体使用参考下面的类型

 

 

 

 函数指针数组

#include <iostream>
int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

int multiply(int a, int b) {
    return a * b;
}

int main() {
    // 创建一个函数指针数组
    int (*operations[3])(int, int) = { add, subtract, multiply };

    int a = 10, b = 5;
    for (int i = 0; i < 3; ++i) {
        std::cout << "Result: " << operations[i](a, b) << std::endl;
    }
    return 0;
}

可以使用typedef简化函数指针的声明和使用

typedef int (*Operation)(int, int);

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

int multiply(int a, int b) {
    return a * b;
}

int main() {
    Operation op;
    op = add;
    std::cout << "Add: " << op(5, 3) << std::endl;

    op = multiply;
    std::cout << "Multiply: " << op(5, 3) << std::endl;

    return 0;
}

函数的三种传递方式(值传递、引用传递、指针传递)

值传递

  • 含义:在使用值传递的时候,函数收到的参数是一个拷贝后的数据,函数内部无论对形参做什么操作都不会影响原始变量的数值
  • 特点
    • 首先是不会改变原始变量的数值
    • 适用于传输比较小的数据类型
void modifyValue(int x) {
    x = 20;  // 仅修改了局部变量 x 的值
}

int main() {
    int a = 10;
    modifyValue(a);
    std::cout << "a: " << a << std::endl;  // 输出 10,a 未被修改
    return 0;
}

引用传递

  • 含义:函数接收的是变量引用,如果对该引用进行修改会影响到之前的原始变量
  • 特点
    • 在传递数据的时候,不需要复制对象,从而可以减少性能消耗
void modifyValue(int& x) {
    x = 20;  // 修改了原始变量的值
}

int main() {
    int a = 10;
    modifyValue(a);
    std::cout << "a: " << a << std::endl;  // 输出 20,a 被修改
    return 0;
}

指针传递

  • 含义:函数中接受的参数是一个地址,函数内可以通过对该地址解应用,从而修改原始变量的数值
  • 特点
    • 使用之前需要进行指针安全性检查防止空指针
    • 可以改变原始变量的数值
void modifyValue(int* x) {
    if (x != nullptr) {
        *x = 20;  // 通过指针修改原始变量的值
    }
}

int main() {
    int a = 10;
    modifyValue(&a);
    std::cout << "a: " << a << std::endl;  // 输出 20,a 被修改
    return 0;
}

 迭代器

迭代器的含义与作用

  • 含义:STL库中提供的一种访问遍历容器中数据的通用方法
  • 作用
    • 遍历容器:提供一种统一的方法去遍历各种容器,不需要关注容器的底层实现细节
    • 访问元素:通过迭代器可以访问容器中的元素,堆目标元素进行读取和修改
    • 插入和删除:特定位置的元素插入和删除操作

迭代器类型

  • 输入迭代器:只读访问,单向移动,用于一次性读取输入
  • 输出迭代器:写访问,用于输出操作
  • 前向迭代器:读写访问,但是只支持单向移动
  • 双向迭代器:读写访问,支持双向移动 

野指针和悬空指针

野指针

  • 含义:未被释放的指针或者已经被释放了内存但是没有被设置为NULL的指针
  • 未初始化的指针:指针在声明的时候,如果没有初始化,那么指针指向的位置是不可控的,所以会造成野指针
  • 内存释放但是指针没有置为NULL:因此该指针还是指向那片被释放的内存,但是该内存已经被释放,所以成为了野指针
  • 野指针的危害
    • 访问未定义的内存,有可能引起程序崩溃
    • 无法预料指针的行为,可能指向重要的内存区域,从而导致数据破坏

 

悬空指针

  • 含义:指针指向已经被释放或者不再有效的内存位置的指针
  • 产生原因
    • 内存释放后继续使用:该指针指向的内存已经被释放了,但是该指针仍然时被继续使用的
    • 局部变量的作用域:指向局部变量的指针在该局部变量作用域结束后继续使用(结合事例理解)
  • 悬空指针的危害:
    • 悬空指针会导致对无效内存的访问,这样会导致程序崩溃或者未定义的行为
    • 也有可能会覆盖其他数据,破坏数据的完整性

 

四种强制类型转换

static_cast:相同类型之间进行转换 

  • 特点
    • 编译时会进行类型检查
    • 运行时不会进行类型检查,向下转换时需要注意(结合事例理解向下转换)

 

 dynamic_cast多态中进行类型转换,比如基类到派生

  • 特点
    • 运行是会进行类型检查会确保转换的安全性
    • 只有当基类有虚函数的时候才会有效(注意)
    • 转换失败时,会返回空指针或者抛出异常

 

const_cast:主要用于移除const或者volatile属性或者是为非const变量添加这些属性

  • 特点
    • 只可以改变const和volatile属性,不可以用于其他类型的转换
    • 不会改变底层的数据结构 

 

reinterpret_cast:用于任何类型的转化,该转换不会进行任何检查,使用的时候需要注意转换的安全性和正确性

  • 特点
    • 限制少,可以用于任何类型的转换
    • 没有类型检查,不保证其安全性,可能会存在未定义的行为 

 

类型萃取

  •  含义:利用模版的特定,根据传入的不同参数,判断其不同的类型,主要是用于STL中的一种技术(比较复杂,该处不深究)
  • 应用场景
    • 泛型编程:根据类型特性进行不同的处理,从而提高代码的通用性和灵活性
    • 类型安全检查:编译期间进行类型检查,从而避免运行时的错误,从而提高程序的安全性
  • 基础类型萃取
    • std::is_integral<T>:判断类型T是否为整型。
    • std::is_floating_point<T>:判断类型T是否为浮点型。
    • std::is_pointer<T>:判断类型T是否为指针类型(根据下面事例进一步理解)

 

结构体相等判断方法分析

结构体逐个成员进行比较:粗暴直接的比较每一个成员是否相等 

struct MyStruct {
    int a;
    float b;
    std::string c;
};

bool areEqual(const MyStruct& lhs, const MyStruct& rhs) {
    return lhs.a == rhs.a && lhs.b == rhs.b && lhs.c == rhs.c;
}

 重载比较运算符:利用运算符重载,从而判断两个结构体是否相等

struct MyStruct {
    int a;
    float b;
    std::string c;

    bool operator==(const MyStruct& other) const {
        return a == other.a && b == other.b && c == other.c;
    }
};

使用标准库函数memcmp,只适用于简单的数据类型,结构体中如果出现指针等就不可以 

#include <cstring>

struct MyStruct {
    int a;
    float b;
};

bool areEqual(const MyStruct& lhs, const MyStruct& rhs) {
    return std::memcmp(&lhs, &rhs, sizeof(MyStruct)) == 0;
}

拓展,直接使用Boost库可以实现两个结构体比较 

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/equal_to.hpp>

struct MyStruct {
    int a;
    float b;
    std::string c;
};

BOOST_FUSION_ADAPT_STRUCT(MyStruct, a, b, c)

bool areEqual(const MyStruct& lhs, const MyStruct& rhs) {
    return boost::fusion::equal_to(lhs, rhs);
}

C++常用的四种模板简述

函数模板: 定义一个通用的函数,函数可以根据指定的类型来推导

 

类模板:定义一个类的通用版本,类的类型参数可以在实例化的时候再进行指定 

别名模板:给模板起一个别名,让模版更加方便的使用 

 

变量模板:用于定义可以接受任何类型参数的常量,很少用

 

 switch语句的case分支是否可以直接定义变量分析

  • 结果:不可以,会导致异常编译错误
  • 原因:因为switch语句中所有的case标签共享同一个作用域,不声明其作用域会造成命名冲突
  • 解决:case后面加一对{},来创建一个新的作用域就可以了

#include <iostream>

void example(int n) {
    switch (n) {
        case 1:
            int a = 10;  // 定义变量 a
            std::cout << "Case 1: " << a << std::endl;
            break;
        case 2:
            int b = 20;  // 这里也定义了变量 b
            std::cout << "Case 2: " << b << std::endl;
            break;
        default:
            std::cout << "Default case" << std::endl;
    }
}

int main() {
    example(1);
    example(2);
    return 0;
}

#include <iostream>

void example(int n) {
    switch (n) {
        case 1: {
            int a = 10;  // 在新的作用域中定义变量 a
            std::cout << "Case 1: " << a << std::endl;
            break;
        }
        case 2: {
            int b = 20;  // 在新的作用域中定义变量 b
            std::cout << "Case 2: " << b << std::endl;
            break;
        }
        default:
            std::cout << "Default case" << std::endl;
    }
}

int main() {
    example(1);
    example(2);
    return 0;
}

可变参数模版 

  • 含义:C++11的一种新模板特性,允许定义任意数量的参数
  • 使用:具体参考代码事例理解

函数模版中可变参数模板的使用事例 

#include <iostream>

// 基础情况:不接受任何参数时终止递归
void print() {
    std::cout << std::endl;
}

// 可变参数模板函数
template <typename T, typename... Args>
void print(T first, Args... args) {
    std::cout << first << " ";
    print(args...); // 递归调用
}

int main() {
    print(1, 2, 3.5, "hello", 'A');
    return 0;

#include <iostream>

// 基础情况:没有参数时返回0
int sum() {
    return 0;
}

// 可变参数模板函数
template <typename T, typename... Args>
int sum(T first, Args... args) {
    return first + sum(args...); // 递归调用
}

int main() {
    std::cout << sum(1, 2, 3, 4, 5) << std::endl; // 输出: 15
    return 0;
}

 类模板的可变参数

 

#include <iostream>
#include <string>

// 基础情况:空的元组
template <typename... Values>
class Tuple;

// 可变参数模板类
template <typename Head, typename... Tail>
class Tuple<Head, Tail...> : private Tuple<Tail...> {
public:
    Tuple(Head head, Tail... tail) : Tuple<Tail...>(tail...), head_(head) {}

    Head head() const { return head_; }
    const Tuple<Tail...>& tail() const { return *this; }

private:
    Head head_;
};

// 终止递归的空元组特化
template <>
class Tuple<> {};

int main() {
    Tuple<int, double, std::string> t(42, 3.14, "hello");
    std::cout << t.head() << std::endl;         // 输出: 42
    std::cout << t.tail().head() << std::endl;  // 输出: 3.14
    std::cout << t.tail().tail().head() << std::endl;  // 输出: hello

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1977393.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Arduino PID库 (2) –微分导致的过冲

Arduino PID库 &#xff08;2&#xff09; – Derivative Kick 参考&#xff1a;手把手教你看懂并理解Arduino PID控制库——微分冲击 pid内容索引-CSDN博客 Arduino PID库 &#xff08;1&#xff09;– 简介 问题 此修改将稍微调整derivative term。目标是消除一种称为“…

RocketMQ消息汇总

当物理文件删除了 队列中的下标的消息也被删除了 但是即使物理删除了 队列中的偏移量还是会持续上升每天凌晨4点 定时清理 在 RocketMQ 中&#xff0c;消息的物理删除是通过定期清理 CommitLog 文件来实现的。CommitLog 文件中存储的是所有主题和队列的消息&#xff0c;一旦这…

关于图片导入Eagle弹出“抱歉,eagle发生了一些问题”的解决办法 | 如何查看Eagle调试报告查询错误文件方法

教程不易&#xff0c;希望得到关注 先说解决办法 使用格式工厂将所有图片或报错图片文件再次转为JPG文件&#xff0c;即可正常导入。 官网入口 http://www.pcgeshi.com/ 吐槽一下现在搜索软件搜“格式工厂官网”第一页全是盗版软件和流氓网页&#xff0c;什么什么金X 风X格式…

使用 Streamlit 和 Python 构建 Web 应用程序

一.介绍 在本文中&#xff0c;我们将探讨如何使用 Streamlit 构建一个简单的 Web 应用程序。Streamlit 是一个功能强大的 Python 库&#xff0c;允许开发人员快速轻松地创建交互式 Web 应用程序。Streamlit 旨在让 Python 开发人员尽可能轻松地创建 Web 应用程序。以下是一些主…

TCP/UDP Socket 测试小工具,作为网工不可以不知道

背景 阿祥今天推荐一款TCP/UDP Socket 测试工具&#xff0c;所谓TCP/IP调试工具是用于在TCP/UDP的应用层上进行通信连接、数据传输的Windows工具。所谓应用层上就是说&#xff0c;TCP调试工具是不涉及TCP/IP协议层实现的问题&#xff0c;而只是利用TCP/IP进行数据传输的工具。 …

建模杂谈系列246 数据模型

说明 如果说微服务化(API接口、Web页面、Docker镜像)是架构方面的基准&#xff0c;那么数据模型就是逻辑处理方面的基准 内容 以下是一个样例&#xff1a; import redef extract_utf8_chars(input_string None):# 定义一个正则表达式&#xff0c;用于匹配所有的UTF-8字符utf…

OpenStack Yoga版安装笔记(十一)nova安装(上)

1、官方文档 OpenStack Installation Guidehttps://docs.openstack.org/install-guide/ 本次安装是在Ubuntu 22.04上进行&#xff0c;基本按照OpenStack Installation Guide顺序执行&#xff0c;主要内容包括&#xff1a; 环境安装 &#xff08;已完成&#xff09;OpenStack…

一文详解大模型蒸馏工具TextBrewer

原文&#xff1a;https://zhuanlan.zhihu.com/p/648674584 本文分享自华为云社区《TextBrewer&#xff1a;融合并改进了NLP和CV中的多种知识蒸馏技术、提供便捷快速的知识蒸馏框架、提升模型的推理速度&#xff0c;减少内存占用》&#xff0c;作者&#xff1a;汀丶。 TextBre…

谷粒商城实战笔记-122~124-全文检索-ElasticSearch-分词

文章目录 一&#xff0c;122-全文检索-ElasticSearch-分词-分词&安装ik分词二&#xff0c;124-全文检索-ElasticSearch-分词-自定义扩展词库1&#xff0c;创建nginx容器1.1 创建nginx文件夹1.2 创建nginx容器获取nginx配置1.3 复制nginx容器配置文件1.4 删除临时的nginx容器…

《Milvus Cloud向量数据库指南》——什么是高可用:深入理解数据库系统中的高可用性架构

什么是高可用:深入理解数据库系统中的高可用性架构 在信息技术日新月异的今天,高可用性(High Availability,简称HA)已成为衡量一个系统,尤其是数据库系统稳定性和可靠性的重要标准。高可用性的核心目标在于确保系统能够持续不断地提供服务,最大限度地减少因维护活动、硬…

从零开始安装Jupyter Notebook和Jupyter Lab图文教程

前言 随着人工智能热浪&#xff08;机器学习、深度学习、卷积神经网络、强化学习、AGC以及大语言模型LLM, 真的是一浪又一浪&#xff09;的兴起&#xff0c;小伙伴们Python学习的热情达到了空前的高度。当我20年前接触Python的时候&#xff0c;做梦也没有想到Python会发展得怎么…

【初阶数据结构题目】10. 链表的回文结构

链表的回文结构 点击链接做题 思路1&#xff1a;创建新的数组&#xff0c;遍历原链表&#xff0c;遍历原链表&#xff0c;将链表节点中的值放入数组中&#xff0c;在数组中判断是否为回文结构。 例如&#xff1a; 排序前&#xff1a;1->2->2->1 设置数组来存储链表&a…

KubeSphere 最佳实战:探索 K8s GPU 资源的管理,在 KubeSphere 上部署 AI 大模型 Ollama

转载&#xff1a;KubeSphere 最佳实战&#xff1a;探索 K8s GPU 资源的管理&#xff0c;在 KubeSphere 上部署 AI 大模型 Ollama 随着人工智能、机器学习、AI 大模型技术的迅猛发展&#xff0c;我们对计算资源的需求也在不断攀升。特别是对于需要处理大规模数据和复杂算法的 AI…

数据恢复软件:电脑丢失文件,及时使用数据恢复软件恢复!

数据恢复软件什么时候会用到&#xff1f; 答&#xff1a;如果真的不小心删除文件&#xff0c;清空回收站&#xff0c;电脑重装系统等情况发生&#xff0c;我们要懂的及时停止使用电子设备&#xff0c;使用可靠的数据恢复软件&#xff0c;帮助我们恢复这些电子设备的数据&#…

【SQL Server 】故障排除:端口冲突排查、网络问题诊断及日志分析与监控6.1 端口冲突排查

目录 第6章&#xff1a;故障排除 端口冲突排查 示例&#xff1a;使用 PowerShell 排查端口冲突 网络问题诊断 示例&#xff1a;使用 Wireshark 捕获 SQL Server 网络流量 日志分析与监控 示例&#xff1a;使用 SQL Server Profiler 监控网络连接 安全注意事项 第6章&am…

Celery:Python异步任务处理的终极利器

文章目录 **Celery&#xff1a;Python异步任务处理的终极利器**第一部分&#xff1a;背景介绍异步任务处理的挑战为什么选择Celery&#xff1f;引入Celery 第二部分&#xff1a;Celery概述什么是Celery&#xff1f; 第三部分&#xff1a;安装Celery使用pip安装Celery 第四部分&…

腰部 KOL 发展潜力预测与企业定制 AI 智能名片 O2O 商城小程序的协同发展

摘要&#xff1a;随着社交媒体和内容创作平台的蓬勃发展&#xff0c;KOL&#xff08;关键意见领袖&#xff09;在品牌推广和营销领域的作用日益凸显。在头部 KOL 资源竞争激烈的当下&#xff0c;腰部 KOL 成为了新的运营重点。然而&#xff0c;挖掘有潜力的腰部 KOL 并非易事。…

【机器学习】重塑游戏世界:机器学习如何赋能游戏创新与体验升级

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀目录 &#x1f50d;1. 引言&#xff1a;游戏世界的变革前夜&#x1f4d2;2. 机器学习驱动的游戏创新&#x1f31e;智能化游戏设计与开发&…

项目实战_图书管理系统(简易版)

你能学到什么 一个简单的项目——图书管理系统&#xff08;浏览器&#xff1a;谷歌&#xff09;基础版我们只做两个功能&#xff08;因为其它的功能涉及的会比较多&#xff0c;索性就放在升级版里了&#xff0c;基础版先入个门&#xff09; 登录: ⽤⼾输⼊账号,密码完成登录功…

华水2022年专升本计算机培养方案

华水2022年专升本计算机培养方案 文章目录 华水2022年专升本计算机培养方案计科第一学期第二学期第三学期第四学期 软工第一学期第二学期第三学期第四学期 计科 第一学期 通识必修课 大学外语线性代数离散数学 专业基础课 高级语言程序设计 专业选修课 Java 第二学期 通识…