C++学习-入门到精通-【5】类模板array和vector、异常捕获
C++学习-入门到精通-【5】类模板array和vector、异常捕获
类模板array和vector、异常捕获
- C++学习-入门到精通-【5】类模板array和vector、异常捕获
- 一、array对象
- array对象的声明
- 使用array对象的例子
- 使用常量变量指定array对象的大小
- 二、基于范围的for语句
- 三、利用array对象存放成绩的GradeBook类
- 四、array对象的排序与查找
- 使用排序和查找的例子
- 五、多维array对象
- 六、利用二维array对象的GradeBook类
- 七、C++标准库类模板vector的介绍
- vector对象和array对象的主要区别
一、array对象
Array是C++标准库中的类模板。array对象是一组具有相同类型的、连续的内存空间。每个array对象都知道自己的大小,可以调用类的成员函数size来确定。例如一个array对象c,使用c.size()
可以获得c的大小。
array对象的声明
使用如下的语法声明一个array对象:
array <类型, 大小> array对象名
;
// 声明一个元素类型为int的,大小为5的array对象
array <int, 5> arr;
尖括号对<>
表明了array是一个类模板。编译器将根据元素的类型和array对象的大小来分配合适的内存空间(一个分配内存的声明,它的更合适的叫法应该是定义)。array对象的大小必须是一个无符号整型。
使用array对象的例子
#include <array>
#include <iostream>
#include <iomanip>using namespace std;int main()
{array<int, 5> arr1;static array<int, 10> arr;cout << setw(7) << "Element" << setw(13) << "Values" << endl;for (int i = 0; i < 5; i++){cout << setw(5) << "arr1[" << i << "]" << setw(13) << arr1[i] << endl;}cout << "\n";for (int i = 0; i < 10; i++){cout << setw(5) << "arr[" << i << "]" << setw(13) << arr[i] << endl;}
}
运行结果:
从结果中看,自动的array对象并不会隐式的初始化为0,静态的array对象会隐式的初始化为0。静态的array对象与静态的局部变量一样,只会在函数第一次调用时进行初始化,之后直到程序结束才会销毁。
使用初始化列表初始化array对象
在array对象的声明中,也可以对其元素进行初始化。具体做法是:在array对象名称的后面加一个等号和一个用逗号分隔的初始化列表,该列表用花括号括起来。
例如:
array <int, 5> a = {};
如果初始化列表中的值的个数小于array对象中元素的个数,那么剩下的对象元素都被初始化为0。上面的例子中,初始化列表中值的个数比array对象中元素的个数少(实际上一个值也没有),所以将没有对应值的元素初始化为0。
注:此方法只能在声明时使用
如果要在非声明的地方初始化array对象的元素,可以使用一个循环语句。
提示:
如果在一个array对象的声明中指定了array对象大小和初始化列表,那么初始化值的个数必须小于或等于array对象的大小。
下面的array对象声明语句就会引起编译错误:
array <int, 5> = { 1,2,3,4,5,6 } // error
使用常量变量指定array对象的大小
在C语言中,使用下面的语句是不被允许的:
const int i = 5;
int arr[i] = { 1,2,3,4,5 }; // error
在C语言中声明一个数组,数组的元素个数必须是一个常量。使用const修饰的变量虽然使用上具有常量的性质(初始化之后无法被修改,但是其本质上仍是一个变量)。
在C++中我们就可以使用常量变量来指定一个array对象的大小,比如:
const int a = 5;
array <int, i> arr = { 1,2,3,4,5 };
但是绝对不能使用变量作为array对象的大小;
注意:使用常量变量时,必须在声明它的时候进行初始化
二、基于范围的for语句
这是一个C++11的新特性,该语句允许程序员不使用计数器就可以完成所有元素的编历,从而避免array缓冲区溢出的可能性,且减少了程序员的工作量(不需要他们自己去实现对边界的检查功能)。
提示:当处理array对象的所有元素时,如果没有访问array对象元素下标的需求,那么使用基于范围的for语句可以较大程度上预防错误的发生
基于范围的for语句的语法形式:
for(范围变量声明 : 表达式)语句
其中范围变量声明中必须包含一个类型名称和一个标识符(例如:int item),表达式是需要迭代遍历的array对象。范围变量声明中的类型必须与array对象的元素类型相一致,而标识符代表循环的连续迭代中下一个array对象的值。
下面给出一个使用基于范围的for语句的例子。
#include <iostream>
#include <array>using namespace std;int main()
{array <int, 5> items = { 1,2,3,4,5 };cout << "items before modification: ";for (int item : items){cout << item << " ";}for (int item : items){item *= 2;}cout << "\nitems after modification(non-reference): ";for (int item : items){cout << item << " ";}for (int& item : items){item *= 2;}cout << "\nitems after modification(reference): ";for (int item : items){cout << item << " ";}
}
运行结果:
可以看到在这种基于范围的for语句中,使用的标识符是array对象的一个副本,对它进行修改并不会对array对象本身的值产生影响。所以这里需要使用引用,来实现对array对象值的修改。
注意:要使用基于范围的for语句,循环对象必须要有begin函数(它是什么我们会在迭代器章节介绍)
三、利用array对象存放成绩的GradeBook类
GradeBook.h
#include <string>
#include <array>class GradeBook
{
public:static const size_t students = 10; // 测试数据,学生人数GradeBook(const std::string &, const std::array<int, students> &);void displayMessage() const;void setCourseName(const std::string &);std::string getCourseName() const;//auto getCourseName() const -> std::string; // 使用之前提到的尾随返回值类型的语法声明get成员函数的返回值类型void processGrades() const;int getMaximum() const;int getMinimum() const;double getAverage() const;void outputBarChart() const;void outputGrades() const;private:std::string CourseName;std::array<int, students> grades; // 保存学生的成绩
};
GradeBook.cpp
#include "GradeBook.h"
#include <iostream>
#include <iomanip>using namespace std;// 构造函数
GradeBook::GradeBook(const string& name, const array<int, students>& gradeArray)// or const array<int, GradeBook::students>& gradeArray) // 在这里不需要使用(类名::数据成员)这样的语法来使用这个数据成员// 因为构造也是类的成员函数,成员函数的作用域中可以直接使用类中的公开数据成员: CourseName(name), grades(gradeArray) // 使用初始化列表初始化两个数据成员
{
}// 打印欢迎信息
void GradeBook::displayMessage() const
{cout << "Welcome to the Grade Book for\n" << getCourseName() << "!" << endl;
}// set成员函数
void GradeBook::setCourseName(const string& name)
{CourseName = name;
}// get成员函数
string GradeBook::getCourseName() const
{return CourseName;
}// 对成绩进行多种操作
void GradeBook::processGrades() const
{// 打印成绩outputGrades();// 打印班级平均成绩cout << setprecision(2) << fixed; // 打印浮点数后面两位,不足补0cout << "\nClass Average is " << getAverage() << endl;// 打印最低成绩和最高成绩cout << "Lowest grade is " << getMinimum() << endl<< "Highest grade is " << getMaximum() << endl;// 打印班级成绩分布条形图outputBarChart();
}int GradeBook::getMaximum() const
{int max = 0; // 成绩是一个非负数,将最大值初始化为0// 不需要考虑数组的下标,只需要遍历数组的每个元素,使用基于范围的for语句// 表达式是要循环的对象,也就是数据成员gradesfor (int grade : grades){if (grade > max){max = grade;}}return max;
}int GradeBook::getMinimum() const
{int min = 100; // 成绩最大值为100,将最小值初始化为100// 不需要考虑数组的下标,只需要遍历数组的每个元素,使用基于范围的for语句for (int grade : grades){if (grade < min){min = grade;}}return min;
}double GradeBook::getAverage() const
{int total = 0;for (int grade : grades){total += grade;}return (static_cast<double>(total) / students);// or return (static_cast<double>(total) / grades.size());// 可以使用array类中提供的成员函数size()来获取array对象中元素的个数// 该值与使用类模板创建一个array对象时的第二个参数相同
}void GradeBook::outputBarChart() const
{cout << "\nGrade distribution:" << endl;// 将成绩分成11个区间// 0-9// 10-19// 20-29// 30-39// ...// 90-99// 100const int frequencySize = 11; // 用一个变量来保存区间数,方便代码的维护array<int, frequencySize> frequency = {}; // 将一个有11个元素的array对象初始化为全0// 用以保存每个区间中学生的人数// 遍历成绩数组,获取每个区间的人数for (int grade : grades){frequency[grade / 10]++;}// 打印条形图for (int i = 0; i < frequencySize; i++){// 打印表头if(i != 10)cout << setw(2) << i * 10 << " - " << setw(3) << 9 + i * 10 << ": ";elsecout << setw(10) << "100: ";// 打印符号*,表示一个人for (int stars = 0; stars < frequency[i]; stars++){cout << "*";}cout << endl;}
}// 打印学生的成绩
void GradeBook::outputGrades() const
{cout << "\nThe grades are: \n";for (int student = 1; student <= grades.size(); student++){cout << "student" << setw(2) << student << ":" << setw(3) << grades[student - 1] << endl;}
}
test.cpp
#include "GradeBook.h"using namespace std;int main()
{// 学生成绩array<int, GradeBook::students> grades = { 87,68,94,100,88,92,78,67,83,98 };// 课程名string CourseName = "CS1201 C++ Programming";// 创建一个GradeBook对象GradeBook myGradeBook(CourseName, grades);myGradeBook.displayMessage();myGradeBook.processGrades();
}
运行结果:
其中使用了array类中的一个成员函数:
注意:类中定义的static的数据成员是所有成员共有的,有const的static数据成员可以在类定义时就初始化,没有const的数据成员必须在类外进行初始化。并不像普通的数据成员一样每一个对象都有一个副本
四、array对象的排序与查找
排序
查找
使用排序和查找的例子
在介绍示例之前我们先看一段代码:
#include <string>
#include <iostream>using namespace std;int main()
{string s1 = "abcf";string s2 = "abcd";if (s1 < s2){cout << "s1 < s2" << endl;}else{cout << "s1 >= s2" << endl;}
}
这段代码在C语言中是不可行的,因为关系运算符是无法比较字符串的大小的,但是C++中引入了运算符重载的概念(后面会介绍),所以string对象的大小可以使用关系运算符进行比较。
#include <iostream>
#include <algorithm>
#include <array>
using namespace std;int main()
{array<int, 5> a = { 5,4,2,3,1 };cout << "Before sort:" << endl;for (int i : a){cout << i << " ";}sort(a.begin(), a.end());cout << "\n\nAfter sort:" << endl;for (int i : a){cout << i << " ";}
}
运行结果:
上面传递给sort函数模板的参数类型如下:
关于begin和end两个函数,我们会在后续介绍迭代器的章节详细说明。
另一个例子:
#include <iostream>
#include <string>
#include <array>
#include <algorithm>using namespace std;int main()
{const int arraySize = 7;array <string, arraySize> colors = { "red", "yellow", "blue", "green", "orange", "indigo", "violet"};cout << "Unsorted array:" << endl;for (string item : colors){cout << item << " ";}sort(colors.begin(), colors.end());cout << "\n\nSorted array:" << endl;for (string item : colors){cout << item << " ";}bool found = binary_search(colors.begin(), colors.end(), "indigo");cout << "\n\n\"indigo\"" << (found? " was " : " was not ")<< "found in colors." << endl;found = binary_search(colors.begin(), colors.end(), "cyan");cout << "\n\n\"cyan\"" << (found ? " was " : " was not ")<< "found in colors." << endl;
}
运行结果:
注意:要利用binary_search函数确定一个值是否在array对象中,前提是该array对象中的值是升序排序好的。该函数并不会检查array对象是否已排序
五、多维array对象
多维的array对象是通过嵌套语句的形式进行声明的。例如:
#include <array>
using namespace std;
// 声明一个二维array对象
array<array<int, 4>, 3> arr = {}; // 所有值初始化为0
const int rows = 2;
const int columns = 3;
array<array<int, columns>, rows> arr2 = { 1,2,3,4,5 };
上面代码定义了一个3行4列的二维array对象,初始化为0。
arr是一个array对象(有3个元素),它的元素的类型也是一个array对象(有4个int类型的元素)。
二维array对象的使用——嵌套的基于范围的for语句
for (const auto& row : arr2)
{for (auto const& column : row){// operation}
}
上面的for语句中,使用auto关键字作为变量的类型,它的含义是让编译器根据该变量初始化值来确定它的数据类型。
六、利用二维array对象的GradeBook类
在上面的GradeBook类的代码中,我们只有一个一维的array对象用来保存成绩,但是一个学期不可能只有一次考试,所以这显然是不够的。
假设一个学期进行4次考试:当前班级中有10个学生,所以我们需要一个10x4的array对象来保存这些数据。
GradeBook.h
#include <string>
#include <array>class GradeBook
{
public:static const size_t students = 10; // 测试数据,学生人数static const size_t tests = 4;GradeBook(const std::string&, const std::array<std::array<int, tests>, students>&);void displayMessage() const;void setCourseName(const std::string&);std::string getCourseName() const;//auto getCourseName() const -> std::string; // 使用之前提到的尾随返回值类型的语法声明get成员函数的返回值类型void processGrades() const;int getMaximum() const;int getMinimum() const;double getAverage(const std::array<int, tests> &) const;void outputBarChart() const;void outputGrades() const;private:std::string CourseName;std::array<std::array<int, tests>, students> grades; // 保存学生的成绩
};
GradeBook.cpp
#include "GradeBook.h"
#include <iostream>
#include <iomanip>using namespace std;GradeBook::GradeBook(const string& name,const array<array<int, tests>, students>& gradeArray)// const array<int, GradeBook::students>& gradeArray) // 在这里不需要使用(类名::数据成员)这样的语法来使用这个数据成员// 因为构造也是类的成员函数,成员函数的作用域中可以直接使用类中的公开数据成员: CourseName(name), grades(gradeArray) // 使用初始化列表初始化两个数据成员
{
}// 打印欢迎信息
void GradeBook::displayMessage() const
{cout << "Welcome to the Grade Book for\n" << getCourseName() << "!" << endl;
}// set成员函数
void GradeBook::setCourseName(const string& name)
{CourseName = name;
}// get成员函数
string GradeBook::getCourseName() const
{return CourseName;
}// 对成绩进行多种操作
void GradeBook::processGrades() const
{// 打印成绩outputGrades();// 打印最低成绩和最高成绩cout << "Lowest grade is " << getMinimum() << endl<< "Highest grade is " << getMaximum() << endl;// 打印班级成绩分布条形图outputBarChart();
}int GradeBook::getMaximum() const
{int max = 0; // 成绩是一个非负数,将最大值初始化为0// 不需要考虑数组的下标,只需要遍历数组的每个元素,使用基于范围的for语句// 表达式是要循环的对象,也就是数据成员gradesfor (auto const& student : grades) // 使用引用,减少复制副本的开销{for (auto const& grade : student){if (grade > max){max = grade;}}}return max;
}int GradeBook::getMinimum() const
{int min = 100; // 成绩最大值为100,将最小值初始化为100// 不需要考虑数组的下标,只需要遍历数组的每个元素,使用基于范围的for语句for (auto const& student : grades) // 使用引用,减少复制副本的开销{for (auto const& grade : student){if (grade < min){min = grade;}}}return min;
}double GradeBook::getAverage(const array<int, tests>& setOfGrades) const
{int total = 0;// 计算一个学生一学期的平均成绩for (auto const& grade : setOfGrades){total += grade;}return (static_cast<double>(total) / tests);// or return (static_cast<double>(total) / setOfGrades.size());// 可以使用array类中提供的成员函数size()来获取array对象中元素的个数// 该值与使用类模板创建一个array对象时的第二个参数相同
}void GradeBook::outputBarChart() const
{cout << "\nGrade distribution:" << endl;// 将成绩分成11个区间// 0-9// 10-19// 20-29// 30-39// ...// 90-99// 100const int frequencySize = 11; // 用一个变量来保存区间数,方便代码的维护array<int, frequencySize> frequency = {}; // 将一个有11个元素的array对象初始化为全0// 用以保存每个区间中学生的人数// 遍历成绩数组,获取每个区间的人数for (auto const& student : grades) // 使用引用,减少复制副本的开销{for (auto const& grade : student){frequency[grade / 10]++;}}// 打印条形图for (int i = 0; i < frequencySize; i++){// 打印表头if(i != 10)cout << setw(2) << i * 10 << " - " << setw(3) << 9 + i * 10 << ": ";elsecout << setw(10) << "100: ";// 打印符号*,表示一个人for (int stars = 0; stars < frequency[i]; stars++){cout << "*";}cout << endl;}
}// 打印学生的成绩
void GradeBook::outputGrades() const
{cout << "\nThe grades are: \n";cout << setw(10) << " "; // 打印表头,对应student idfor (int i = 0; i < tests; i++){cout << setw(5) << "Test" << setw(2) << i + 1;}cout << setw(9) << "Average" << endl;// 输出所有学生的成绩for (int student = 1; student <= grades.size(); student++){cout << "student" << setw(2) << student << ":" ;// 输出一个学生的所有成绩for (int test = 0; test < tests; test++){cout << setw(7) << grades[student - 1][test];}// 输出该学生的平均成绩cout << setprecision(2) << fixed << setw(9) << getAverage(grades[student - 1]) << endl;}
}
test.cpp
#include "GradeBook.h"using namespace std;int main()
{// 学生成绩array<array<int, GradeBook::tests>, GradeBook::students> grades = {87, 96, 70, 97,68, 87, 90, 93,94, 100, 90, 98,100, 82, 81, 92,83, 65, 83, 80,78, 87, 65, 81,67, 78, 85, 90,77, 79, 63, 88,99, 100, 95, 96,85, 83, 79, 90};// 课程名string CourseName = "CS1201 C++ Programming";// 创建一个GradeBook对象GradeBook myGradeBook(CourseName, grades);myGradeBook.displayMessage();myGradeBook.processGrades();
}
运行结果:
七、C++标准库类模板vector的介绍
vector对象的声明语法:
vertor<类型> 名称(大小);
示例代码
#include <iostream>
#include <vector>using namespace std;void outputVector(const vector<int> &);
void inputVector(vector<int> &);int main()
{// 与array类模板的声明类似,在<>中指定保存元素的类型,但是容量在变量名后指定vector<int> integer1(7); // 创建一个有7个int类型元素的vector对象vector<int> integer2(10); // 创建一个有7个int类型元素的vector对象// 输出两个vector对象的大小及默认初始值cout << "\nSize of vector integer1 is " << integer1.size() << endl<< "vector after initialization:";outputVector(integer1);cout << "\nSize of vector integer2 is " << integer2.size() << endl<< "vector after initialization:";outputVector(integer2);// 输出17个整数用于初始化两个vector对象cout << "Enter 17 ingeters:" << endl;inputVector(integer1);inputVector(integer2);// 输出赋值后的vector对象的值cout << "\nAfter input, the vectors contain:\n"<< "integer1:" << endl;outputVector(integer1);cout << "integer2:" << endl;outputVector(integer2);cout << "\nEvaluation: integer1 != integer2" << endl;if (integer1 != integer2){cout << "integer1 and integer2 are not equal" << endl;}// 创建一个新vector对象,并使用integer1赋值vector<int> integer3(integer1);cout << "\nSize of vector integer3 is " << integer3.size() << endl<< "vector after initialization:";outputVector(integer3);// 对vector对象直接使用'='进行赋值cout << "\nAssigning integer2 to integer1: " << endl;integer1 = integer2;cout << "integer1:" << endl;outputVector(integer1);cout << "integer2:" << endl;outputVector(integer2);cout << "\nEvaluation: integer1 == integer2" << endl;if (integer1 == integer2){cout << "integer1 and integer2 are equal" << endl;}cout << "\ninteger1[5] is " << integer1[5] << endl;cout << "\n\nAssigning 1000 to integer1[5]." << endl;integer1[5] = 1000;cout << "integer1:" << endl;outputVector(integer1);// 异常处理,访问越界try {cout << "\n\nAttempt to display integer1.at(15)." << endl;cout << integer1.at(15) << endl; // error,越界}catch (out_of_range &ex){cerr << "An exception occured: " << ex.what() << endl;}cout << "\nCurrent Size of integer3 is " << integer3.size() << endl;integer3.push_back(1000); // 在integer3的末尾添加一个元素3cout << "New integer3 size is " << integer3.size() << endl;cout << "integer3 now contains: " << endl;outputVector(integer3);
}void outputVector(const vector<int>& array)
{// 使用基于范围的for语句遍历整个vector对象for (int item : array){cout << item << " ";}cout << endl;
}void inputVector(vector<int>& array)
{for (int item : array){cin >> item;}
}
运行结果:
代码中使用的库函数:
从上面的程序执行结果可以看出,vector对象可以使用关系运算符进行比较操作。
一个vector对象可以用另一个vector对象进行初始化。也可以使用一个vector对象为另一个vector对象赋值。
还可以像数组一样使用[]
和下标来访问指定的vector元素,但是在使用[]
进行访问时,C++是不会进行边界检查的。但是在vector类提供的at函数中,是提供了边界检验功能的。
异常处理:处理超出边界的下标
异常是一个在程序运行时出现的问题的表现。异常处理使程序员能够创建可以解决(或处理)异常的容错程序。在很多情况下,在处理异常的同时还允许程序继续运行,就像没有遇到异常一样。
try语句:
为了处理一个异常需要把可能抛出一个异常的任何代码放置在一个try语句中。
catch语句:
包含了发生异常时,负责处理异常的代码。
比如,上面例子中try语句中包含了一个调用vector类的at成员函数的语句,该函数提供了边界检查和抛出异常的功能,当这个函数的实参是一个无效下标时,就会抛出一个异常。在默认的情况下这会导致C++程序终止。在这里下标15显然不是一个有效的下标,所有异常出现,由该try语句对应的catch语句来处理这个异常。
从上面的库函数介绍图中,可以看出,at函数抛出的异常是out_of_range
类型的异常。所以在上面代码的catch语句指定了处理的异常的类型为out_of_range
,且声明了一个用于接收引用的异常形参ex
。在这个语句块中,可以使用形参的标识符来实现与捕捉到的异常对象的交互。
注意,try和catch是两个不同的语句块,它们的作用域不同,在try中声明的变量无法在catch中使用。
异常形参的what函数:
在上面的代码中调用了这个异常对象的what成员函数,来得到并显示存储在此异常对象中的错误信息。
更详细的异常处理内容会在之后的章节中说明。
vector对象和array对象的主要区别
vector对象和array对象的一个主要区别就是vector对象可以动态增长以容纳更多元素。
使用成员函数push_back
可以为vector对象增加一个元素,对应的可以使用pop_back
这个成员函数删除vector对象中的一个元素。
除了像上面一样使用for循环语句对vector对象进行初始化,还可以使用初始化列表对vector对象进行初始化。例如:
#include <iostream>
#include <vector>using namespace std;int main()
{vector<int> integer4 = { 1,2,3,4,5 };// or vector<int> integer4{1,2,3,4,5};for (int item : integer4){cout << item << " ";}
}
上面这段代码中,使用初始化列表将vector对象integer4初始化为有5个元素vector对象。
相关文章:
C++学习-入门到精通-【5】类模板array和vector、异常捕获
C学习-入门到精通-【5】类模板array和vector、异常捕获 类模板array和vector、异常捕获 C学习-入门到精通-【5】类模板array和vector、异常捕获一、array对象array对象的声明使用array对象的例子使用常量变量指定array对象的大小 二、基于范围的for语句三、利用array对象存放成…...
`待办事项css样式
vue <template> <div class"box"> <div class"head"> <h2>待办事项</h2> <input type"text" placeholder"请输入您的待办事项,按回车添加"> </div> <div class"main&q…...
spring ai alibaba 使用 SystemPromptTemplate 很方便的集成 系统提示词
系统提示词可以是.st 文件了,便于修改和维护 1提示词内容: 你是一个有用的AI助手。 你是一个帮助人们查找信息的人工智能助手。 您的名字是{name} 你应该用你的名字和{voice}的风格回复用户的请求。 每一次回答的时候都要增加一个65字以内的标题形如:【…...
Vue3 官方宣布淘汰 Axios,拥抱Alova.js
过去十年,Axios 凭借其简洁的API设计和浏览器/Node.js双环境支持,成为前端开发者的首选请求库。但随着现代前端框架的演进和工程化需求的升级,Alova.js 以更轻量、更智能、更符合现代开发范式的姿态登场。 一、Axios的痛点 1,冗余的适配逻辑,比如Axios的通用配置(但实际…...
2025年数维杯C题数据收集方式分享
2025年数维杯C题”清明时节雨纷纷,何处踏青不误春?“需要我们根据题目的要求自行数据,下图为目前已经收集到的问题一二数据集,本文将为大家详细的介绍具体收集数据方式以及处理方式。 通过网盘分享的文件:分享数据集 …...
手写 vue 源码 === ref 实现
目录 响应式的基本实现 Proxy 与属性访问器 Proxy 的工作原理 属性访问器(Getter/Setter) 为什么解构会丢失响应性 ref 和 toRefs 的解决方案 proxyRefs:自动解包 ref 总结 Vue3 的响应式系统是其核心特性之一,它通过 Pro…...
Python爬虫抓取Bilibili弹幕并生成词云
1. 引言 Bilibili(B站)是国内知名的视频分享平台,拥有海量的弹幕数据。弹幕是B站的核心特色之一,用户通过弹幕进行实时互动,这些数据对于分析视频热度、用户情感倾向等具有重要价值。 本文将介绍如何利用Python爬虫技…...
【Python 字典(Dictionary)】
Python 中的字典(Dictionary)是最强大的键值对(key-value)数据结构,用于高效存储和访问数据。以下是字典的核心知识点: 一、基础特性 键值对存储:通过唯一键(Key)快速访…...
k8s之探针
探针介绍: 编排工具运行时,虽说pod挂掉会在控制器的调度下会重启,出现pod重启的时候,但是pod状态是running,无法真实的反应当时pod健康状态,我们可以通过Kubernetes的探针监控到pod的实时状态。 Kubernetes三种探针类…...
upload-labs靶场通关详解:第三关
一、分析源代码 代码注释如下: <?php // 初始化上传状态和消息变量 $is_upload false; $msg null;// 检查是否通过POST方式提交了表单 if (isset($_POST[submit])) {// 检查上传目录是否存在if (file_exists(UPLOAD_PATH)) {// 定义禁止上传的文件扩展名列表…...
LeetCode:101、对称二叉树
递归法: /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {…...
zst-2001 历年真题 UML
UML - 第1题 ad UML - 第2题 依赖是暂时使用对象,关联是长期连接 依赖:依夜情 关联:天长地久 组合:组一辈子乐队 聚合:好聚好散 bd UML - 第3题 adc UML - 第4题 bad UML - 第5题 d UML - 第6题 …...
对称加密以及非对称加密
对称加密和非对称加密是两种不同的加密方式,它们在加密原理、密钥管理、安全性和性能等方面存在区别,以下是具体分析: 加密原理 对称加密:通信双方使用同一把密钥进行加密和解密。就像两个人共用一把钥匙,用这把钥匙锁…...
Java反射 八股版
目录 一、核心概念阐释 1. Class类 2. Constructor类 3. Method类 4. Field类 二、典型应用场景 1. 框架开发 2. 单元测试 3. JSON序列化/反序列化 三、性能考量 四、安全与访问控制 1. 安全管理器限制 2. 打破封装性 3. 安全风险 五、版本兼容性问题 六、最佳…...
C++跨平台开发实践:深入解析与常见问题处理指南
一、跨平台开发基础架构设计 1.1 跨平台架构的核心原则 分层设计模式: 平台抽象层(PAL):将平台相关代码集中管理 核心逻辑层:完全平台无关的业务代码 平台实现层:针对不同平台的特定实现 代码组织最佳实践: pro…...
【“星睿O6”AI PC开发套件评测】+ MTCNN 开源模型部署和测试对比
经过了前几篇文章的铺垫,从搭建 tensorflow 开发环境,到测试官方 onnx 模型部署到 NPU,接着部署自己的 mnist tensorflow 模型到 NPU。这是一个从易到难的过程,本篇文章介绍开源复杂的人脸识别模型 mtcnn 到 “星睿O6” NPU 的部署…...
JAVA实战开源项目:装饰工程管理系统 (Vue+SpringBoot) 附源码x
本文项目编号 T 179 ,文末自助获取源码 \color{red}{T179,文末自助获取源码} T179,文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...
centos 7 安装 java 运行环境
centos 7 安装 java 运行环境 java -version java version "1.8.0_131" Java(TM) SE Runtime Environment (build 1.8.0_131-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)java -version java version "1.8.0_144" Java(TM) …...
力扣题解:21.合并两个有序链表(C语言)
将两个升序链表合并为一个新的升序链表是一个经典的链表操作问题。可以通过递归或迭代的方法来解决。以下是解释和代码实现: 递归: 每次比较两个链表的头节点,将较小的节点添加到新链表中,并递归处理剩余部分。 截至条件…...
iOS App 安全性探索:源码保护、混淆方案与逆向防护日常
iOS App 安全性探索:源码保护、混淆方案与逆向防护日常 在 iOS 开发者的日常工作中,我们总是关注功能的完整性、性能的优化和UI的细节,但常常忽视了另一个越来越重要的问题:发布后的应用安全。 尤其是对于中小团队或独立开发者&…...
SpringBoot默认并发处理(Tomcat)、项目限流详解
SpringBoot默认并发处理 在 Spring Boot 项目中,默认情况下,同一时间能处理的请求数由内嵌的 Tomcat 服务器的线程池配置决定。 默认并发处理能力 请求处理流程 请求到达:新请求首先进入 TCP 连接队列(最大 ma…...
Xterminal(或 X Terminal)通常指一类现代化的终端工具 工具介绍
Xterminal(或 X Terminal)通常指一类现代化的终端工具,旨在为开发者、运维人员提供更高效、更智能的命令行操作体验。 📢提示:文章排版原因,资源链接地址放在文章结尾👇👇ÿ…...
如何把win10 wsl的安装目录从c盘迁移到d盘
标题:如何把win10 wsl的安装目录从c盘迁移到d盘 通过microsoft store安装的 wsl 目录默认在 C:\Users[用户名]\AppData\Local\wsl 下 wsl的docker镜像以及dify的编译环境会占用大量硬盘空间,0.15.3 、1.1.3、1.3.1 三个版本的环境占用空间超过40GB [图…...
2025医疗信息化趋势:健康管理系统如何重构智慧医院生态
当北京协和医院的门诊大厅启用智能分诊机器人时,距离其3000公里外的三甲医院正通过健康管理系统将慢性病复诊率降低42%。这场静默发生的医疗革命,正在重新定义2025年智慧医院的建设标准。 一、穿透数据孤岛的三大核心引擎 最新版《智慧医院评价指标体系…...
java volatile关键字
volatile 是 Java 中用于保证多线程环境下变量可见性和禁止指令重排序的关键字。 普通变量不加volatile修饰有可见性问题,即有线程修改该变量值,其他线程无法立即感知该变量值修改了。代码: private static int intVal 0; // 普通变量未加 …...
中阳策略模型:结构节奏中的方向感知逻辑
中阳策略模型:结构节奏中的方向感知逻辑 在交易世界中,“节奏”与“结构”的互动远比大多数人想象得复杂。中阳研究团队在大量实战数据分析中提出一个核心观点:方向感的建立,必须以结构驱动为前提,以节奏确认为依据。 …...
死锁的形成
死锁的形成 背景学习资源死锁的本质 背景 面试可能会被问到. 学习资源 一个案例: https://www.bilibili.com/video/BV1pz421Y7kM 死锁的本质 互相持有对方的资源. 存在资源竞争都没有释放. 可能出现死锁. insert into demo_user (no, name) values (6, ‘test1’) on dupl…...
每天五分钟深度学习框架pytorch:视觉工具包torchvison
本文重点 在pytorch深度学习框架中,torchvision是一个非常优秀的视觉工具包,我们可以使用它加载一些著名的数据集,然后我们可以使用它来加载网络模型,比如vgg,resnet等等,还可以使用它来预处理一些图片数据,本节课程我们将学习一下它的使用方式。 torchvision的四部分…...
C++之运算符重载实例(日期类实现)
日期类实现 C 日期类的实现与深度解析一、代码结构概览1.1 头文件 Date.h1.2 源文件 Date.cpp 二、关键函数实现解析2.1 获取某月天数函数 GetMonthDay2.2 构造函数 Date2.3 日期加减法运算2.4 前置与后置自增/自减操作2.5 日期比较与差值计算 三、代码优化与注意事项3.1 代码优…...
数据分析怎么做?高效的数据分析方法有哪些?
目录 一、数据分析的对象和目的 (一)数据分析的常见对象 (二)数据分析的目的 二、数据分析怎么做? (一)明确问题 (二)收集数据 (三)清洗和…...
数组和切片的区别
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…...
【Linux】自定义shell的编写
📝前言: 这篇文章我们来讲讲【Linux】简单自定义shell的编写,通过这个简单的模拟实现,进一步感受shell的工作原理。 🎬个人简介:努力学习ing 📋个人专栏:Linux 🎀CSDN主页…...
【C/C++】为什么要noexcept
为什么要noexcept 在C中,noexcept修饰符用于指示函数不会抛出异常 1. 性能优化 减少异常处理开销:编译器在生成代码时,若函数标记为noexcept,可以省略异常处理的相关机制(如栈展开代码),从而减…...
运用fmpeg写一个背英文单词的demo带翻译
-男生会因为不配而离开那个深爱的她吗?? 一, fmpeg-7.0.1 是做什么用的?? FFmpeg 7.0.1 是 FFmpeg 的一个版本,FFmpeg 是一个开源的多媒体框架,用于处理音视频数据。FFmpeg 提供了强大的工具和…...
Android 项目中配置了多个 maven 仓库,但依赖还是下载失败,除了使用代理,还有其他方法吗?
文章目录 前言解决方案gradlemaven 仓库 前言 我们在Android 开发的过程中,经常会遇到三方依赖下载不下来的问题。一般情况下我们会在项目的build.gradle文件中配置多个 maven 仓库来解决。 // Top-level build file where you can add configuration options com…...
vue3: pdf.js5.2.133 using typescript
npm install pdfjs-dist5.2.133 项目结构: <!--* creater: geovindu* since: 2025-05-09 21:56:20* LastAuthor: geovindu* lastTime: 2025-05-09 22:12:17* 文件相对于项目的路径: \jsstudy\vuepdfpreview\comonents\pdfjs.vue* message: geovindu* IDE: vscod…...
doxygen 生成 html 网页的一个简单步骤
假设项目源码目录是 src 那么在 src 上一级运行: doxygen -g生成 Doxyfile 随后配置 Doxyfile # 项目相关配置 PROJECT_NAME "你的项目名称" PROJECT_NUMBER "1.0" PROJECT_BRIEF "项目简短描述" …...
云原生环境下服务治理体系的构建与落地实践
📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:服务治理正在从“框架能力”向“平台能力”演进 随着微服务架构逐步成熟,越来越多的企业开始向云原生迁移,Kubernetes、Service Mesh、Serverless 等新兴技术不断推动系统的基础设施演进。 与…...
vue 监听元素大小变化 element-resize-detector
1,安装 npm install element-resize-detector --save2、设置成全局插件 element-resize-detector.js: import ElementResizeDetectorMaker from element-resize-detectorexport default {install: function(Vue, name $erd) {Vue.prototype[name] …...
智芯Z20K144x MCU开发之时钟架构
这里写目录标题 一、zhixin时钟架构1.时钟源2.系统时钟控制器(SCC)3.外设时钟控制器(PARCC) 二、软件应用三、总结 一、zhixin时钟架构 可以将时钟架构分解为三个部分来理解: 时钟源(OSC、FIRC、LPO&#…...
levelDB的数据查看(非常详细)
起因:.net大作业天气预报程序(WPF)答辩时,老师问怎么维持数据持久性的,启动时加载的数据存在哪里,我明白老师想考的应该是json文件的解析(正反),半天没答上来存那个文件了(老师默认这个文件是自…...
OpenHarmony平台驱动开发(十),MMC
OpenHarmony平台驱动开发(十) MMC 概述 功能简介 MMC(MultiMedia Card)即多媒体卡,是一种用于固态非易失性存储的小体积大容量的快闪存储卡。 MMC后续泛指一个接口协定(一种卡式)࿰…...
【Go底层】http标准库服务端实现原理
目录 1、背景2、核心数据结构【1】Server对象【2】Handler对象【3】ServeMux对象 3、服务端代码示例4、路由注册5、路由匹配 1、背景 http协议的交互框架是C-S架构,C对应客户端模块,S对应服务端模块,接下来我们就基于Go1.23源码来熟悉http标…...
现代健康养生新主张
在充满挑战与压力的现代生活中,健康养生已成为提升生活品质的关键。无需复杂的理论与传统养生模式,通过践行以下科学方法,便能轻松拥抱健康生活。 压力管理是现代养生的核心。长期高压力状态会引发激素失衡、免疫力下降等问题。尝试每天进…...
Spring 必会之微服务篇(1)
目录 引入 单体架构 集群和分布式架构 微服务架构 挑战 Spring Cloud 介绍 实现方案 Spring Cloud Alibaba 引入 单体架构 当我们刚开始学开发的时候,基本都是单体架构,就是把一个项目的所有业务的实现功能都打包在一个 war 包或者 Jar 包中。…...
创始人 IP 的破局之道:从技术突围到生态重构的时代启示|创客匠人评述
在 2025 年的商业版图上,创始人 IP 正以前所未有的深度介入产业变革。当奥雅股份联合创始人李方悦在 “中国上市公司品牌价值榜” 发布会上,将 IP 赋能与城市更新大模型结合时,当马斯克在特斯拉财报电话会议上宣称 “未来属于自动驾驶和人形机…...
C++ stl中的stack和queue的相关函数用法
文章目录 stackstack的定义stack的使用 queuequeue的定义queue的使用 stack的使用 包含头文件< stack > #include <stack>queue的使用 包含头文件< queue > #include <queue>stack stack是一种容器适配器,用于具有后进先出操作的场景中&…...
Navicat BI 数据分析功能上线 | 数据洞察新方法
Navicat 17.2 版本一经发布,便以 AI 助手赋能智能交互、Snowflake 支持拓展数据连接版图、拓展对关系型、维度以及数据仓库 2.0 建模方法的支持等新特性与功能抓住了用户的目光,但其中一项低调且实用的更新 - 在 BI 数据预览中深度集成数据分析工具&…...
【网络编程】四、守护进程实现 前后台作业 会话与进程组
文章目录 Ⅰ. 守护进程的概念Ⅱ. 理解会话和作业🎏 会话和进程组的特性小总结Ⅳ. 作业的前后台转换1、fg 指令2、bg 指令 Ⅴ. 守护进程实现1、常见接口① 创建守护进程 -- daemon② 自成会话函数 -- setsid③ 获取会话ID函数 -- getsid 2、自主实现守护进程函数 Ⅰ.…...
【深度学习新浪潮】智能追焦技术全解析:从算法到设备应用
一、智能追焦技术概述 智能追焦是基于人工智能和自动化技术的对焦功能,通过深度学习算法识别并持续跟踪移动物体(如人、动物、运动器械等),实时调整焦距以保持主体清晰,显著提升动态场景拍摄成功率。其核心优势包括: 精准性:AI 算法优化复杂运动轨迹追踪(如不规则移动…...