C++ primier plus 函数探幽第二部分
系列文章目录
C++ primer plus 第一节 步入C++-CSDN博客
C++ primer plus 第二节 hello world刨析-CSDN博客
C++ primer plus 第三节 数据处理-CSDN博客
C++ primer plus 第四节 复合类型-CSDN博客
C++ primer plus 第五节 循环-CSDN博客
C++ primier plus 第七节 函数探幽第一部分-CSDN博客
目录
系列文章目录
前言
一 引用的绪论
二 引用 类 继承
三 默认参数
四 右值 左值 左引用 右引用
五 函数的重载
六 函数模板
七 重载的模板
八 函数模板的局限性质
九 实例化和具体化
总结
前言
这里是上一篇文章的绪论,其实还要写一篇,太多知识点了,这个本书很难,只能说作者看的要废了,然后这个是基于作者的理解,然后部分后面讲的省掉了,只找重点,让我们理解这里面的重点知识
一 引用的绪论
1 将引用运用到结构体
其实引用就是运用在结构体和类里面的
使用结构体引用参数的方式与变量引用基本相同,只需要在使用的时候加一个运算符&就好了,
例如struct free throws { std: :string name; int made; ìnt attempts; float percent; };我们就以这个为例子写一个关于结构体引用的知识点的程序
display(accumulate(team, two));我们可以看到有三个功能函数
这个结构体的含义是每一个人都有成功次数和尝试次数,然后计算出百分比
set_pc是用来进行进行计算百分比的
这个不能用按值传递的,我们直接用引用吗,这样就可以直接对one进行操作了,另外一个操作就是指针写法了,我们可以感受到这样写很简单便捷
display是用来进行显示的
这里直接用const修饰就好,因为我要确定好那些要加const,那些不需要加const,加了const是不需要进行修改的,没有加是一般是要对其有修改操作的
computer是计算一个小组里面的整体的百分比和各个数值的
我们需要操作的six是直接进行引用不加const的
但是我们不需要进行操作的one是直接加上const的,这样安全性更高
当然还有别的写法,由于虚拟机太麻烦了,好难敲,所以我就直接在这里说了display(accumulate(team, two));这个就是我的computer函数,但是我的修改一下,返回值为结构体引用,加一个return就好了,然后就是直接利用返回值就好了
accumulate (accumulate (team, three) , four);这个也就是利用返回值的类型和第一个形参的返回值类型相同,这样我们就可以提高自己写代码的效率,等效于下面这个代码
accumulate (team, three) ; accumulate (team, four) ;首先我们总结一下我们这里所学到的知识点
👉1 我们可以利用返回值类型和形参类型相同,进行代码的简化
👉2 为什么要返回引用类型?
首先我们直到我们在返回操作的时候,是需要额外开辟一个变量进行存储,然后在赋值个那个对应的变量的,这样就可以减少开销
👉3 返回时候需要注意的问题const free throws & clone2(free throws & ft){ free_throws newguy; // first step to big error newguy = ft; // copy info return newguy; // return reference to copy }我们看我们这里也是返回了结构体引用类型,但是这个是返回其他函数里面其他函数的临时结构体变量,但是这个变量函数销毁的时候会没有的,那么就是返回一个空,就是什么也没有了,那么就是返回不了
👉4 const的使用
我们在使用const修饰的时候是需要好好考虑的,需要考虑这个是否需要修改,还要考虑这个安全性
2 将引用用于类对象
将类对象传递给函数时, C++通常的做法是使用引用。例如,可以通过使用引用,让函数将类string、ostream、 lstream、 ofstream 和 ifstream 等类的对象作为参数
下面来看一个例子,它使用了 string 类,并演示了一些不同的设计方案,其中的一些是糟糕的
这个是用来进行对于字符串的升级
首先我们我们这里由三个升级方式,接下来我们会一个一个讲解
首先第一个升级方式version1
这里是创建了一个临时的变量temp,然后利用字符串的运算,然后得到最后升级之后的字符串
第二个升级方式version2
这里形参是利用了引用,一个是带有const,一个是不带有const修饰的
然后就是直接对上面的变量进行操作,所以input被改变了,注意返回类型,这个s1是存在的,所以可以返回
第三个升级方式version3
这里也是利用引用,但是是用了一个临时变量,这里返回类型也是引用就是犯了我上面说的错误,类似于指针的错误,野指针,但是不是完全是,只是有点像
这里是类的操作的话,还行跟讲结构体差不多,但是我们往深入想就又会又疑问
❌ 注意事项
首先我们上面的*** ### @@@都是char*类型,但是这里形参类型是string,我们需要怎么理解呢?
首先,C++定义了一个由char*类型可以转换到string类型,这使得C-风格字符串类型来初始化string对象
其次就是const形参得一个属性就是,假设形参和实参得类型不匹配得话,但是可以转换为与引用类型相同的类型,因为可以创建一个临时的变量进行存储,这样就可以利用引用引用那个临时变量
二 引用 类 继承
首先在ostream和ofstream类凸显了一个引用的一个有趣的属性,ofstream对象可以使用ostream类的方法,这使得文件输入和输出的格式与控制台输入输出的形式是相同的,使得能够将特性从一个类传递给另一个类的语言特性被称作继承
ostream是基类,ofstream是派生类,派生类继承了基类的方法,这意味ofstream可以使用ostream类的方法
派生类的对象可以使用基类的方法
这个继承后续会仔细进行讲解,这里只需要了解这么多就好了
总的来说,派生类可以使用基类的方法,并且使用的方法格式都是一样的,如意味着ofstream 对象可以使用基类的特性,如格式化方法precision()和 setf( ),还要理解派生类和基类的具体的概念是干嘛的
这里主要是理解,继承的另一个特征,基类引用可以指向派生类对象,而无需进行强制类型转换。这种特征的一个实 际结果是,可以定义一个接受基类引用作为参数的函数,调用该函数时,可以将基类对象作为参数,也可 以将派生类对象作为参数总的来说就是可以用基类引用作为一个函数的参数,传参的时候可以是派生类还可以是基类
接下来用一个物镜目镜求取焦距的程序来梳理这个知识
这里说明一下,这本书用来很多的格式化输出,这个是我们还没有学习的,而且后面还会讲解,所以这里是删改版本,我们这里主要是学习基类引用与派生类和基类的关系
前面加一个函数声明,作者忘记加了
然后我们可以看到这个
代码的上面是创建fstream变量和判断是否可以打开这个文件,这个代码才是关键,我们自己写一个函数,然后是这样的
这个第一个形参是基类的引用,我们上面学习了,基类的引用是可以接受派生类和基类传参的,所以这里我们直接用基类的引用就好了,这里主要是学习这个
何时使用引用参
使用引用参数的主要原因有两个:
程序员能够修改调用函数中的数据对象
通过传递引用而不是整个数据对象,可以提高程序的运行速度|
当数据对象较大时(如结构和类对象),第二个原因最重要。这些也是使用于指针参数的原因。这是有道理的,因为引用参数实际上是基于指针的代码的另一个接口。
那么,什么时候应使用引用、什么时候应使用指针呢?什么时候应按值传递呢?
下面是一些指导原则:
对于使用传递的值而不作修改的函数
如果数据对象很小,如内置数据类型或小型结构,则按值传递。
如果数据对象是数组,则使用指针,因为这是唯一的选择,并将指针声明为指向 const的指针。
如果数据对象是较大的结构,则使用 const指针或const引用,以提高程序的效率。这样可以节省 复制结构所需的时间和空间。
如果数据对象是类对象,则使用 const 引用。类设计的语义常常要求使用引用这是 C++新增这 项特性的主要原因
因此,传递类对象参数的标准方式是按引用传递
对于修改调用函数中数据的函数:
如果数据对象是内置数据类型,则使用指针。如果看到诸如 fixit(&x)这样的代码〈其中x是int), 则很明显, 该函数将修改x
如果数据对象是数组,则只能使用指针
如果数据对象是结构,则使用引用或指针
如果数据对象是类对象,则使用引用
三 默认参数
C++新增了一个内容——默认参数
比如我们由一个函数wow(int n),我们在调用这个函数的时候,没有进行给n进行设置值,那么这个n就会使用默认参数,比如这个这个n的默认参数为1,那么我们在调用的时候,用wow()这个形式,那么这个就是为1
下面我们将一个具体的例子
比如由一个这个函数left("theory",3)我们在传参的时候,这个意思就是我要取第几个字母,那么这个运行出来取了theory的e这个字母,假设这个函数的默认参数为1,那么我们调用的时候,使用left("theory")的时候,我们直接取出来t这个字母
这个默认参数给我们提供了一个很大的便捷的方式,如果程序每次都是取出一个字母,而不是一个长的字符串,那么就是极大减少了我们的操作
怎么设置默认参数
首先这个默认参数的设置是在函数的原型进行设置的,即函数的声明那里,比如void left(char* str, int n = 1);这个例子就是设置默认参数n为1,那么我们下面以一个实际的程序来理解默认参数
![]()
![]()
我们可以看到上面这个代码,首先这个main函数有两个实例的程序,一个是取到第四个字母,就是从第一个取到第四个字母,然后第二个样例就是使用默认参数来输出,这个默认参数在函数原型进行设置了,为1
然后我们来看一下这个left功能函数,这个函数的主要功能为把对应的字母放入到new开辟的空间里面,然后利用循环进行输出
第一个for循环是i<n的时候就直接停止,但是第二个条件是用来干嘛的呢?
如果我们输入了一个本身字符串还大的值,比如10000,如果没有第二个条件,那么程序运行会出错,所以我们这个作用是弄到规定的字符串大小就进行停止
第二个while就是把我们后面没有弄到的设置为\0,这样有利于cout识别输出,因为cout是根据\0识别进行输出的
程序效率的修改
我们来看这个程序就是这个new开辟如果我们输入10000,那么是不是有很多的内存浪费,所以我们想要有一个节省内存的
方法一
这个是根据strlen进行计算元素的具体大小来进行判断,但是这个过程有函数调用的开销和返回值的保存这样就会导致效率降低,但是内存省了很多
我们既要节省内存也要体高效率就直接进行自己的书写
我们直接用这个程序就好了计算m的大小,当满足上述条件就好了
小结
我们直到默认参数的设置与好处,还用了一个程序来举例
其次就是我们学习了前面的知识,我们不仅要写出代码,还要提高函数的效率,这样才可以加深我们的知识的运用
四 右值 左值 左引用 右引用
由于函数的重载在这个没有很详细的介绍,导致后面很多都看不懂,所以为了理解函数的重载,我们这里先理解这个,这个右引用这里先知道,后面会进行很详细的介绍
左值和右值int a = 10; int b = a; int c = (a+b);a+c = c; 10 = a;我们先来看几个代码
a=10,这个10就是右值,这个a就是左值
b=a,这个b就是左值,a就是右值,这个是比较特殊的例子
c=a+b,这个就是c就是左值,a+b就是右值
但是不可以像我们最后两个所写的这样
所以我们可以得出一个小的结论
左值一般都是可以取地址的,右值一般都是不可以取地址的
左引用和右引用int b = 10; int a = 10; int& e = b;int& c = 10; int& d = (a+c); const int& o = 10; const int& p = (a+c);首先第三行的是我们很常规的写法,这个就是对于一个变量的引用嘛,这个右边的不就是我们上面所说的左值嘛,那么这个就是左值引用
但是我们看到第四个和第五个的时候就是右边是右值,这个就是不正确的,因为我们这个是左值引用
根据前面所学的就是前面加一个const就可以了,这个是用了一个临时变量,然后引用那个临时变量,但是这个有个缺点就是无法修改,这可以读取,那么就是推出了右值引用int a = 10; int b = 10; int &&c = 10; int &&d = (a+b);这个就是右值引用,这个我们就可以看懂我们书本后面的代码了,这个就可以修改那个右值嘛
五 函数的重载
C++在C的基础上新加上了一个功能,这个功能的名字也是十分的便于理解,就是一个函数的名称可以在多次的使用,默认参数让您能够使用不同数目的参数调用同一个 函数,而函数多态(函数重载〉让您能够使用多个同名的函数,这个函数的多态也就是函数的重载,只是函数的重载更加标准
函数重载的标准特征——函数的参数列表
参数的个数是使用边缘器进行计算得出来的
函数参数列表的不同包括:1 参数的个数 2 参数的顺序 3 参数的类型
然后我会分别举例出函数重载的问题情况
1 函数重载的样例
这个是一些函数重载的样例
这个十分的简单,我们下面来看一些比较容易出错的
2 函数未找到对应的参数类型
比如这个我想在上面那五个函数里找打,这个usigned int是未找到的,那么这个时候你以为编译器停止这个工作进行报错了嘛?其实不然
它不与任何原型匹配! 没有匹配的原型并不会自动停止使用其中的某 个函数,因为C++将尝试使用标准类型转换强制进行匹配。 如果#2原型是print()唯一的原型,则函数调用 print(year, 6)将把 year 转换为 double 类型
但是读者可能去尝试之后还是会报错,不是都说可以进行强制转换了嘛?为什么还是会进行报错?原因就是这里有2,3,4这三个都可以进行转换,那么C++就会不接受这种传参形式,也因此会进行报错,除非只有一个可以进行转换的
3 引用
当我们在使用函数重载里面放入引用这个时候有相同的类型,那么这个时候其实编译器是视为一样的,那么也会提示报错,因为不是唯一的,这里要特别注意,因为后续使用引用的情况特别多,所以就很容易出错
4 const和非const
首先编译器不会进行const与非const的区分,但里面还是会有一些需要注意的东西
首先函数的参数是由const修饰,那么你传参数,char和const char都是寻找const char进行函数调用
但是你的函数参数是char,那么const char就不行,const char会去寻找带有const的,但是char会去寻找不带有const的
5 重载引用参数
函数重载的特别
首先我们看到这个,也就是说左值引用会去找左值,右值引用则会去寻找右值,但是右值找不到右值引用的时候,就会去找带有const的函数
C++函数重载里面有一个很神奇的东西,虽然你写的名称是一样的,但是也会进行名词修饰或名称矫正
名称矫正或者名词修饰就是指把函数的名称进行稍微的修改
六 函数模板
我们直到函数的重载,那么我们知道,当我们在改写很多的不同的数据类型的时候,是要进行复制黏贴,这样的操作虽然可以实现函数名字的不冲突,但是用起来还是十分的麻烦,有时候后面的代码可能产生错误信息,那么我们就又引入了一个新的特性——函数模板
我们知道C++是支持泛型编程的,所以支持泛型编程的话,那么也就存在一个函数可以使用多个类型的传参template <typename AnyType> void Swap (AnyType &a, AnyType &b){ AnyType temp; temp = a; a = b; b = temp;}下面这个代码是一个函数模板的样例,这个首先要用到这个template,然后后面写一个typename 然后类型的名字,一般程序员会把这个名字简化写出T
然后我们在看别的代码的时候也会遇到或者typename写成class,这个是C++98之前所使用的了,然后这里C++98之后就加上了typename这个东西
首先我们在书写这个类型的时候,我们一般都是建议输入typename的
如果需妥多个将同一种算法用于不同类型的函数,请使用模板。 如果不考虑向后兼容的问题, 并愿意键入较长的单词,则声明类型参数时,应使用关键字可pename而不使用 class
下面这是根据函数模板进行编写的程序#include<iostream> #include<string> using namespace std;template <typename T> void Iswap(T& a, T& b) {T temp = a;a = b;b = temp; }int main() {int a = 10;int b = 20;Iswap(a, b);cout << "This is int swap : " << endl;cout << "a = " << a << " b = " << b << endl;double x = 19.8;double y = 20.9;Iswap(x, y);cout << "This is double swap : " << endl;cout << "x = " << x << " y = " << y << endl;return 0; }我们可以看到这个函数的模板函数是怎么设置的
其实我们函数模板每次调用一个不同类型的数据的时候,都是会创建一个新的函数来进行接受,这个发生在编译阶段,就比如我们这里就会有一个int类型的交换函数,还有一个double类型的交换函数,这个的存在就是为了避免函数重载写多个有代码的陈杂,然后就是减少出错的几率,更安全,更可靠
七 重载的模板
我们学习过函数的模板和函数的模板,那么重载模板就是对函数的模板进行重载,我们上述是可以进行交换值,如int, char, double, float, long这几个类型,但是对于数组的时候就不行了,但是算法还是相同的,那么我们就对模板进行重载
下面我们来对上面那个函数的模板进行重载#include<iostream> #include<string> using namespace std;template <typename T> void Iswap(T a[], T b[], T n) {for (int i = 0; i < n; i++) {T temp = a[i];a[i] = b[i];b[i] = temp;} }template <typename T> void Iswap(T& a, T& b) {T temp = a;a = b;b = temp; }void show(int a[], int n) {for (int i = 0; i < n; i++)cout << a[i] << " ";cout << endl; }int main() {int a = 10;int b = 20;Iswap(a, b);cout << "This is int swap : " << endl;cout << "a = " << a << " b = " << b << endl;double x = 19.8;double y = 20.9;Iswap(x, y);cout << "This is double swap : " << endl;cout << "x = " << x << " y = " << y << endl;int n = 6;int ao[6] = { 1,2,3,4,5,6 };int bo[6] = { 6,5,4,3,2,1 };cout << "array a : " << endl;show(ao, n);cout << "array b : " << endl;show(bo, n);cout << "This is a swap array : " << endl;Iswap(ao, bo, n);cout << "array a : " << endl;show(ao, n);cout << "array b : " << endl;show(bo, n);return 0; }这里是实现数组的互换的,我们可以看到我们实现重载的模板
八 函数模板的局限性质
我们在声明函数模板的时候,前面的声明是需要数学template <typename T>的
下面我们来看一个代码#include<iostream> #include<string> using namespace std;struct Cengineer {string name;int salary;int floor; };template <typename T> void Iswap(T& a, T& b);void show(Cengineer people);int main() {int a = 10;int b = 20;Iswap(a, b);cout << "This is int swap : " << endl;cout << "a = " << a << " b = " << b << endl;double x = 19.8;double y = 20.9;Iswap(x, y);cout << "This is double swap : " << endl;cout << "x = " << x << " y = " << y << endl;Cengineer Jake = { "Jake",10000,10 };Cengineer Mike = { "Mike",11000,15 };cout << "engineer's job and salary : " << endl;show(Jake);show(Mike);cout << "swap data : " << endl;show(Jake);show(Mike);return 0; }void show(Cengineer people) {cout << "name : " << people.name << " salary : " << people.salary << " floor : " << people.floor << endl;}template <typename T> void Iswap(T& a, T& b) {T temp = a;a = b;b = temp; }首先我们可以看到我们这一次交换的是结构体,但是我想的是利用这个Iswap进行交换,但是结果是名字,薪水,楼层都被互换了,所以导致交换失败,这个时候我们就想到利用函树的重载,但是,我们知道我们声明的时候还是这个形式
template <typename T> void Iswap(T& a, T& b);这就使这个重载不了,我们上面也学习过,引用是不会作为特征进行处理的,所以这里我们就会陷入困境
那么这个时候就会有显示具体化
显示具体化
什么是显示具体化呢?
C++可以提供一个具体化函数定义一一称为显式具体化 (explicitspecialization), 其中包含所需的代 码。当编译器找到与函数调用匹配的具体化定义时,将使用该定义,而不再寻找模板
我们以一个例子来讲解#include<iostream> #include<string> using namespace std;struct Cengineer {string name;int salary;int floor; };template <typename T> void Iswap(T& a, T& b); template <> void Iswap<Cengineer>(Cengineer& a, Cengineer& b); void show(Cengineer people);int main() {int a = 10;int b = 20;Iswap(a, b);cout << "This is int swap : " << endl;cout << "a = " << a << " b = " << b << endl;double x = 19.8;double y = 20.9;Iswap(x, y);cout << "This is double swap : " << endl;cout << "x = " << x << " y = " << y << endl;Cengineer Jake = { "Jake",10000,10 };Cengineer Mike = { "Mike",11000,15 };cout << "engineer's job and salary : " << endl;show(Jake);show(Mike);cout << "swap data : " << endl;show(Jake);show(Mike);return 0; }void show(Cengineer people) {cout << "name : " << people.name << " salary : " << people.salary << " floor : " << people.floor << endl;}template <typename T> void Iswap(T& a, T& b) {T temp = a;a = b;b = temp; }template <> void Iswap<Cengineer>(Cengineer& a, Cengineer& b) {int c = 0;int d = 0;c = a.salary;a.salary = b.salary;b.salary = c;d = a.floor;a.floor = b.floor;b.floor = a.floor; }看到这一个
template <> void Iswap<Cengineer>(Cengineer& a, Cengineer& b);这个是用来进行显示具体化的声明
这个template的尖括号里面是不需要输入任何东西,然后这个后面要加一个尖括号,里面写上具体的类型,这样就可以让编译器知道哪一种是需要额外进行操作的,然后就把这个传进去进行操作就好了
编译器是先执行显示化还是先执行模板呢?
试验其他具体化方法后, C++锦标准选择了下面的方法
• 对于给定的函数名,可以有非模板函数、模板函数和显式具体化模板函数以及它们的重载版本
• 显式具体化的原型和定义应以template<>打头,并通过名称来指出类型
• 具体化优先于常规模板,而非模板函数优先于具体化和常规模板
九 实例化和具体化
定义
编译器使用模板为特定类型生成函数定义时,得到的是模板实例(instantiation )。例如,在程序中,函数调用 Swap(i,j)导致编译器生成 Swap( )的一个实例,该实例使用int类型。模板并非函数定义,但使用int的模板实例是函数定义,这种实例化方式被称为隐式实例化, 因为编译器之所以知道需要进行定义,是由于程序调用 Swap( )函数时提供了 mt参数。 最初,编译器只能通过隐式实例化,来使用模板生成函数定义,但现在C++还允许显式实例化Cexplicit instantiation) 。这意味着可以直接命令编译器创建特定的实例,如 Swap( )。其语法是,声明所需的种 类一一用o符号指示类型,并在声明前加上关键字templatetemplate void Swap<int>(int , int); // explicit instantiation这个就是模板的实例化
然后我们对比一下具体化有什么不用呢?template <> void Swap<int> (int &, int &); // explicit specialization template <> void Swap(int &, int &); // explicit specialization综上所述
实例化分为隐式实例化和显示实例化,隐式实例化就是指当你必须传递参数,告知这个参数的类型为什么的时候,这个时候编译器才会把这个模板里面的int类型的函数实例化,但是显示实例化,无论你有没有传递参数,这个编译器都会进行实例化
具体化是用在告诉编译器这个需要进行特殊的处理
显示实例化声明的是,前面的template是不带有尖括号的
总结
引用的绪论
我们可以知道结构体和类的引用的使用方法,什么时候使用引用
引用我们需要注意的就是const修饰,返回值的类型,用const修饰的时候,计算机会进入哪一些操作,提示临时变量
引用,类,继承
我们这里需要知道基类,派生类是什么含义
基类的引用作为形参的话,进行传实参的时候,既可以是派生类或者基类
继承的简介,就是可以让派生类使用基类的特性
什么时候使用值传递,什么时候使用指针传递,什么时候使用引用传递
默认参数
默认参数的使用是在函数原型的时候,给变量赋予初始值,然后当我们不在这个函数的默认参数进行传值的话,那么就是使用默认参数,当我们传参的时候,传入了值,那么这个默认参数是会被掩盖的,这个是运用到重载和安全还有就是便捷
左值,右值,左值引用,右值引用
函数的重载
函数的重载就是可以避免函数的名字冲突,这里里卖弄的函数特征是函数的参数列表
包括个数,数量,类型,接下里就是几个特例
引用和相同类型
const修饰
当未找到参数类型时候,就会判断是否可以进行强制转换,如果没有或者有多个可以,那么就是直接进行报错
函数的模板
由于函数的重载很容易报错,就有了这个模板
template <typename T>
void swap(T &a,T &b);template <typename T>
void swap(T &a,T &b){······
}
这个是函数模板
重载的模板
由于函数模板有时候处理不了更多的数据,那么这个时候就会由一个重载,这个就是修改一下函数里面形参的内容,就好了,跟函数的重载一样的
函数模板的局限性
当我们无法进行重载的时候,我们就要考虑使用显示具体化了,这个就是可以帮助我们对于单独一个类型进行书写
template <> void swap <int> (int &a ,int &b){.......
}
实例化和显示具体化
这个就是一个概念
template void Swap<int>(int , int); // explicit instantiation
实例化分为隐式实例化和显示实例化,隐式实例化就是指当你必须传递参数,告知这个参数的类型为什么的时候,这个时候编译器才会把这个模板里面的int类型的函数实例化,但是显示实例化,无论你有没有传递参数,这个编译器都会进行实例化
具体化是用在告诉编译器这个需要进行特殊的处理
显示实例化声明的是,前面的template是不带有尖括号的
相关文章:
C++ primier plus 函数探幽第二部分
系列文章目录 C primer plus 第一节 步入C-CSDN博客 C primer plus 第二节 hello world刨析-CSDN博客 C primer plus 第三节 数据处理-CSDN博客 C primer plus 第四节 复合类型-CSDN博客 C primer plus 第五节 循环-CSDN博客 C primier plus 第七节 函数探幽第一部分-CSDN博客 …...
DBus名词术语命名规范详解:构建清晰、规范的DBus通信
引言 DBus(Desktop Bus)是一种高效、灵活的进程间通信(IPC)机制,广泛应用于Linux桌面环境中。为了确保DBus通信的清晰性和规范性,DBus定义了一套严格的命名规范,涵盖了总线、服务名、对象路径、…...
用低代码平台集成人工智能:无需专业开发也能实现智能化
引言:人工智能的普及与企业需求 随着人工智能(AI)技术的飞速发展,越来越多的企业开始意识到其在提升运营效率、优化客户体验和推动业务创新方面的巨大潜力。从智能客服到自动化决策支持,从数据分析到个性化推荐&#x…...
Java停车平台高并发抢锁技术方案设计 - 慧停宝开源停车管理平台
Java停车平台高并发抢锁技术方案设计 一、业务场景特征 瞬时流量峰值 早晚高峰时段(07:30-09:00, 17:30-19:00)请求量激增10倍热门商圈停车场每秒并发请求可达5000 QPS 资源竞争特性 单个车位被多人同时抢占(超卖风险)用户操作链…...
C++关键字:typename 用于依赖名消歧器(disambiguator)
目录 1. 说明 2. 示例 1. 说明 在模板(包括别名模板)的声明或定义中,非当前实例的成员且依赖于模板参数的名称不视为类型,除非使用关键字 typename 或除非它已被建立为类型名称(例如使用 typedef 声明或用于命名基…...
第六课:数据库集成:MongoDB与Mongoose技术应用
本文详细介绍了如何在Node.js应用程序中集成MongoDB数据库,并使用Mongoose库进行数据操作。我们将涵盖MongoDB在Ubuntu 20系统中的安装、Bash命令的CRUD操作、Mongoose数据建模(Schema/Model)、关联查询与聚合管道,以及实战案例—…...
TypeError: Cannot set properties of undefined (setting ‘xxx‘)
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》、《前端求职突破计划》 🍚 蓝桥云课签约作者、…...
Gravitino源码分析-SparkConnector 实现原理
Gravitino SparkConnector 实现原理 本文参考了官网介绍,想看官方解析请参考 官网地址 本文仅仅介绍原理 文章目录 Gravitino SparkConnector 实现原理背景知识-Spark Plugin 介绍(1) **插件加载**(2) **DriverPlugin 初始化**(3) **ExecutorPlugin 初始化**(4) *…...
windows下使用msys2编译ffmpeg
三种方法: 1、在msys2中使用gcc编译 2、在msys2中使用visual studio编译(有环境变量) 3、在msys2中使用visual studio编译(无环境变量) 我的环境: 1、msys2-x86_64-20250221 2、vs2015 3、ffmpeg-7.1…...
Linux内核自定义协议族开发指南:理解net_device_ops、proto_ops与net_proto_family
在Linux内核中开发自定义协议族需要深入理解网络协议栈的分层模型。net_device_ops、proto_ops和net_proto_family是三个关键结构体,分别作用于不同的层次。本文将详细解析它们的作用、交互关系及实现方法,并提供一个完整的开发框架。 一、核心结构体的作用与层级关系 struct…...
可视化+图解链表
链表(Linked list)是一种常用的数据结构,它由一系列节点组成,每个节点包含数据域和指针域。指针域存储了下一个节点的地址,从而建立起各节点之间的线性关系。 1、链表节点 1.1 节点构成 链表节点如下图所示ÿ…...
Docker参数,以及仓库搭建
一。Docker的构建参数 注释: 1.对于CMD,如果不想显示,而是使用交互界面:docker run -ti --rm --name test2 busybox:v5 sh 2.对于CMD,一个交互界面只可以使用一个,如果想多次使用CMD,则用ENTR…...
正十七边形尺规作图证明——从高斯的发现到几何实现
正十七边形尺规作图证明——从高斯的发现到几何实现 1. 引言:一个历史性的数学突破 在欧几里得几何中,尺规作图(仅使用直尺和圆规)是最为基础的几何构造方法。古希腊数学家已知如何构造正三角形、正方形和正五边形,但…...
常见Web应用源码泄露问题
文章目录 前言一、常见的源码泄露漏洞git源码泄露SVN源码泄露DS_Store文件泄漏网站备份压缩文件泄露WEB-INF/web.xml泄露CVS泄露.hg源码泄露Bazaar/bzr泄露.swp文件泄露 前言 在Web应用方面对于安全来说,可能大家对SQL注入、XSS跨站脚本攻击、文件上传等一些漏洞已…...
如何使用 Python+Flask+win32print 实现简易网络打印服务1
Python 实现网络打印机:Flask win32print 在工作场景中,我们可能需要一个简单的网页接口,供他人上传文档并自动打印到指定打印机。 本文将演示如何使用 Python Flask win32print 库来实现这一需求。 代码详见:https://github.…...
使用Modelsim手动仿真
FPGA设计流程 在设计输入之后,设计综合前进行 RTL 级仿真,称为综合前仿真,也称为前仿真或 功能仿真。前仿真也就是纯粹的功能仿真,主旨在于验证电路的功能是否符合设计要求,其特点是不考虑电路门延迟与线延迟。在完成一个设计的代码编写工作之后,可以直接对代码进行仿真,…...
DeepSeek、Grok与ChatGPT:AI三巨头的技术博弈与场景革命
## 引言:AI工具的三国杀时代 2025年的AI江湖,DeepSeek以黑马之姿横扫全球应用榜单,Grok 3凭借马斯克的狂言抢占头条,ChatGPT则稳坐行业王座。这场技术竞赛不仅是参数量的比拼,更是一场关于效率、成本与场景适配的终极…...
windows自动锁屏,并且要输入密码。如何取消?
Windows 电脑自动锁屏并需要输入密码,通常是因为系统的 电源和睡眠设置 或 组策略 设定了自动锁屏。你可以按照以下方法取消自动锁屏或去掉密码要求: 方法 1:修改 Windows 设置 取消锁屏时间 Win I 打开 设置,进入 系统 → 电源和…...
Redis 主从复制、哨兵与集群的关系及工作原理详解
一、核心概念与关系 Redis 的 主从复制、哨兵(Sentinel) 和 集群(Cluster) 是逐步演进的高可用与分布式解决方案,三者关系如下: 主从复制:数据冗余与读写分离的基础。 哨兵:在主从…...
XSD 对 XML 数据格式验证 java
xsd文件,文件名bean.xsd,放在当前java文件目录下 <?xml version"1.0" encoding"UTF-8"?> <xs:schema xmlns:xs"http://www.w3.org/2001/XMLSchema"><xs:element name"bean"><xs:comple…...
利用 ArcGIS Pro 快速统计省域各市道路长度的实操指南
在地理信息分析与处理的工作中,ArcGIS Pro 是一款功能强大的 GIS 软件,它能够帮助我们高效地完成各种复杂的空间数据分析任务。 现在,就让我们一起深入学习如何借助 ArcGIS Pro 来统计省下面各市的道路长度,这一技能在城市规划、…...
1.4 单元测试与热部署
本次实战实现Spring Boot的单元测试与热部署功能。单元测试方面,通过JUnit和Mockito等工具,结合SpringBootTest注解,可以模拟真实环境对应用组件进行独立测试,验证逻辑正确性,提升代码质量。具体演示了HelloWorld01和H…...
蓝桥杯备考:六级词汇积累(day5)
dense 稠密的 condense 压缩 compassion 同情,怜悯 compact 紧凑的,紧密的 resent 愤恨 sober 清醒的 sole 唯一的,独占的 solely only solemn 表情严肃的,庄重的 stun 使昏迷 Stunned by the impact, he lay on the ground won…...
掌握Kubernetes Network Policy,构建安全的容器网络
在 Kubernetes 集群中,默认情况下,所有 Pod 之间都是可以相互通信的,这在某些场景下可能会带来安全隐患。为了实现更精细的网络访问控制,Kubernetes 提供了 Network Policy 机制。Network Policy 允许我们定义一组规则,…...
结合rpart包的决策树介绍
决策树与CART算法 决策树是一种基于树状结构的监督学习算法。它通过从根节点开始递归地对特征进行划分,构建出一棵树来进行决策。决策树的构建过程需要解决的重要问题有三个:如何选择自变量、如何选择分割点、确定停止划分的条件。解决这些问题是希望随…...
VScode代码格式化插件black失效问题
之前有如下提示: 没太当回事,发现还能用。之后突然就用不了了,跟着官方插件的文档来查看log: 查看发现提示: Message: TypeError: type object is not subscriptable 在github界面找到解决方案:安装Versio…...
【经验分享】Ubuntu20.04编译RK3568 AI模型报错问题(已解决)
【经验分享】Ubuntu20.04编译RK3568 AI模型报错问题(已解决) 前言问题现象问题分析解决方案总结 前言 这里使用的是Rockchip提供的rknn_model_zoo,https://github.com/airockchip/rknn_model_zoo/tree/main 此解决方案适用于Rockchip芯片在U…...
AI革命先锋:DeepSeek与蓝耘通义万相2.1的无缝融合引领行业智能化变革
云边有个稻草人-CSDN博客 目录 引言 一、什么是DeepSeek? 1.1 DeepSeek平台概述 1.2 DeepSeek的核心功能与技术 二、蓝耘通义万相2.1概述 2.1 蓝耘科技简介 2.2 蓝耘通义万相2.1的功能与优势 1. 全链条智能化解决方案 2. 强大的数据处理能力 3. 高效的模型…...
基于SpringBoot实现旅游酒店平台功能一
一、前言介绍: 1.1 项目摘要 随着社会的快速发展和人民生活水平的不断提高,旅游已经成为人们休闲娱乐的重要方式之一。人们越来越注重生活的品质和精神文化的追求,旅游需求呈现出爆发式增长。这种增长不仅体现在旅游人数的增加上࿰…...
轻松上手 —— 通过 RPM 包快速部署 NebulaGraph
前言 在当今大数据时代,处理复杂关系数据的需求与日俱增,图数据库应运而生并逐渐崭露头角。NebulaGraph 作为一款高性能、分布式且易扩展的图数据库,专为应对大规模图数据处理而精心打造。它不仅具备丰富的查询语言,还拥有强大高效…...

代码的上面是创建fstream变量和判断是否可以打开这个文件,这个代码才是关键,我们自己写一个函数,然后是这样的
这个是根据strlen进行计算元素的具体大小来进行判断,但是这个过程有函数调用的开销和返回值的保存这样就会导致效率降低,但是内存省了很多
我们直接用这个程序就好了计算m的大小,当满足上述条件就好了
这个是一些函数重载的样例




