C++ 函数学习笔记

news/2024/5/17 21:17:10/文章来源:https://blog.csdn.net/qq_37701948/article/details/127012783

前言:主要是自己学习过程的积累笔记,所以跳跃性比较强,建议先自学后拿来作为复习用。

文章目录

  • 1 函数基础
  • 2 参数传递
    • 2.1 const 形参和实参
    • 2.2 引用形参
    • 2.3 数组形参
    • 2.4 数组引用形参
    • 2.5 多维数组形参
    • 2.6 可变形参
  • 3 返回类型和 return 语句
    • 3.1 无返回值
    • 3.2 有返回值
    • 3.3 返回引用
    • 3.4 列表初始化返回值
    • 3.5 递归
    • 3.6 返回数组指针
      • 3.6.1 声明一个返回数组指针的函数
      • 3.6.2 使用尾置返回类型
      • 3.6.3 使用 decltype
        • 练习
  • 4 函数重载
  • 5 特殊用途语言特性
    • 5.1 默认实参
    • 5.2 内联函数和 constexpr 函数
    • 5.2.1 内联函数
    • 5.2.2 constexpr 函数
  • 6 函数指针
    • 6.1 使用函数指针
    • 6.2 重载函数的指针
    • 6.3 函数指针形参
    • 6.4 返回指向函数的指针

1 函数基础

典型的函数定义:返回类型 函数名字 圆括号(由0个或多个用逗号隔开形参列表) {函数体},比如:

int function(int parameter1, int parameter2, ...)
{...return XXX;
}

典型的函数调用:函数名 圆括号(由0个或多个用逗号隔开的实参列表),比如:

int a = function(argument1, argument2, ...);

函数调用完成两项工作:

  • 用实参初始化函数对应的形参;
  • 将控制权转移给被调函数。

此时,主调函数的执行被暂时中断,被调函数开始执行。

函数执行完后,return 语句完成两项工作:

  • 返回 return 语句中的值(如果有的话);
  • 将控制权从被调函数转移回主调函数。

函数的调用规定实参数量应与形参数量一致,且实参的类型必须与形参类型相匹配,所以形参一定会被初始化。函数的返回类型不能是数组或者函数,但可以是指向数组或函数的指针。

在形参和函数体内部定义的变量统称为局部变量,仅在函数的作用域内可用,程序从函数中退出时即被销毁;在所有函数体之外定义的对象称为全局变量,它们在程序启动时创建,在程序结束时销毁。若要令局部变量的生命周期贯穿函数调用及之后的时间(即在程序结束时才被销毁),可以将其定义为局部静态变量。如下所示:

int func()
{static int cnt = 0; // 函数调用结束后,这个值仍然有效return cnt++;
}

有一点要注意的是,若循环调用上面的函数,cnt 只有在程序第一次调用 func 函数时会被创建并分配空间,在此后的每次调用都不会重复创建,实际生效的语句是 cnt++,也就是说 cnt 的值在循环调用之后会越来越大。但是,在 func 函数之外的其他任何地方都用不了 cnt 变量,仅仅在 func 函数内 cnt 的值是一直有效的。

对于大的工程项目,在头文件中声明函数和变量,在源文件中进行定义是一个比较合理且容易管理项目的方法。

2 参数传递

当形参是引用类型时,我们说它对应的实参被引用传递或者函数被传引用调用,此时,引用形参是实参的别名;当形参为非引用类型时,形参和实参是两个相互独立的对象,此时称实参被值传递或者函数被传值调用

2.1 const 形参和实参

当形参有顶层 const 时,传给它常量对象或者是非常量对象都是可以的。例如:

void function(const int i) { /* fcn 能够读取 i,但是不能改变 i 的值 */}

调用 function 函数时,既可以传入 int,也可以传入 const int。实参初始化形参时会忽略掉顶层 const,这时就会出现一种情况:C++ 中的重载函数要求形参列表不一致,但由于顶层 const 被忽略了,所以下面的两条语句会被视作同一个函数从而报错:

void function(const int i) { /* fcn 能够读取 i,但是不能改变 i 的值 */}
void function(int i) { /*...*/ } // 错误,重复定义了 fcn(int i)

关于 const 的相关知识可以参考博客:C++ const 限定符学习笔记,写的非常详细。

2.2 引用形参

不推荐把函数中不会改变的形参定义成普通的引用(即非常量引用)。使用非常量引用也会极大地限制函数所能接受的实参类型,因为常量引用可以接受各种类型的实参,但非常量引用不能接受 const 对象、字面值或者需要类型转换的对象。

2.3 数组形参

数组的两个性质:不允许拷贝数组以及使用数组时通常会将其转换成指针使得我们无法以值传递的方式使用数组形参,当我们为函数传递一个数组时,实际上传递的是指向数组首元素的指针

可以把形参写成类似数组的形式:

// 下面三个函数是等价的
void fcn(const int*)
void fcn(const int[])
void fcn(const int[10])

有三种方式管理数组的指针形参防止越界:

  1. 使用标记指定数组长度

该方法要求数组本身就包含一个结束标记,比如 C 语言字符串的末尾有一个空字符 ‘\0’。这种方法适用于那些有明显结束标记且该标记不会与普通数据混淆的情况。

  1. 使用标准库规范

该方法向函数传递数组首元素和尾后元素的指针,如下面的函数:

void print(const int *beg, const int *end)
{// 输出 beg 到 end 之间(不含 end)的所有元素while (beg != end)cout << *beg++ << endl; // 输出当前元素并将指针向前移动一个位置
}

为了调用这个函数就需要传入两个指针,一个指向首元素,另一个指向为尾元素的下一个位置:

int sample[2] = {0, 1};
print(begin(sample), end(sample));
  1. 传递数组大小的形参

在函数的形参列表定义一个表示数组大小的形参。因此上面的 print 函数可改写成如下形式:

// const int *a 等价于 const int a[]
void print(const int a[], int size) { /*...*/ }

同理,如果函数不需要改变数组元素时,指针形参应写成指向常量的指针。

2.4 数组引用形参

见下面的例子:

// 正确:形参是数组的引用,维度是类型的一部分
void print(int (&arr)[10])
{for (auto elem : arr)cout << elem << endl;
}

注意:&arr 两端的括号必不可少

void print(int &arr[10])		// 错误:将 arr 声明成了10个引用构成的数组
void print(int (&arr)[10])	// 正确:arr 是具有10个整数的整型数组的形参

该写法的缺陷在于它无形中限制了函数的可用性,比如上述的 print 函数就只能作用于大小为10的数组。

2.5 多维数组形参

C++ 中没有真正的多维数组,只有数组的数组。将多维数组传递给函数时,传递的其实是指向数组首元素的指针。因为处理的是数组的数组,所以首元素本身就是一个数组,指针就是一个指向数组的指针。

// matrix 指向数组的首元素,该数组的元素是由10个整数构成的数组
void print(int (*matrix)[10], int rowSize) { /*...*/ }
// 等价定义
void print(int matrix[][10], int rowSize) { /*...*/ }

*matrix 两端的括号必不可少

void print(int *matrix[10])		// 错误:将 matrix 声明成了10个指针构成的数组
void print(int (*matrix)[10])	// 正确:matrix 是指向含有10个整数的数组的指针

2.6 可变形参

要编写能处理不同数量实参的函数,主要有两种方法。

  • initializer_list 形参

如果函数的实参数量未知全部实参的类型都相同,就可以使用 initializer_list 类型的形参。它是一种标准库类型,主要提供以下操作:

#include<initializer_list> // initializer_list 类型的头文件initializer_list<T> lst;				默认初始化;T类型元素的空列表
initializer_list<T> lst{a, b, c...};	lst 的元素数量和初始值一样多;lst 的元素是对应初始值的副本;列表中的元素是 const
lst2(lst)			拷贝或赋值一个 initializer_list 对象不会拷贝列表中的元素;拷贝后,原始列表和副本共享元素
lst2 = lst			等价于上句
lst.size()			返回列表中的元素数量
lst.begin()			返回指向 lst 中首元素的指针
lst.end()			返回指向 lst 中尾元素下一位置的指针

类似于 vector,initializer_list 也是一种模板类型。定义 initializer_list 对象时必须说明列表中的元素类型:

initializer_list<string> ls;	// initializer_list 的元素类型是 string
initializer_list<int> li;		// initializer_list 的元素类型是 int

不同于 vector 的地方在于 initializer_list 中的元素都是常量值,无法改变。

因此要给函数传递未知数量的实参时,可以将函数改写成如下的形式:

void function(initializer_list<int> il) { /*...*/ }

若想向 initializer_list 形参传递一个值的序列,则需要把序列放在花括号中:

function({1, 2, 3});
  • 省略符形参

省略符形参是为了便于 C++ 访问某些特殊的 C 代码而设置的,它们使用了名为 varargs 的 C 标准库功能。省略符形参只能出现在形参列表的最后面,有以下两种形式:

void function(parameter_list, ...);
void function(...);

前者指定了部分形参的类型,只有这部分形参需要进行类型检查(编译器要检查实参和形参的类型是否一致),而省略符形参对应的实参无需类型检查。

3 返回类型和 return 语句

return 语句的两种类型:

return;				// 第一种形式
return expression;	// 第二种形式

3.1 无返回值

第一种形式只能用在返回类型是 void 的函数,但返回 void 的函数不要求非得有 return 语句。即使没有的话,它们也会在函数体的最后一句隐式的执行 return。而 return 用在返回 void 的函数中的主要作用是退出函数。所以也可以将其用在函数执行过程中来提前退出函数。

但返回 void 的函数也不是不能用第二种形式,此时 expression 必须是另一个返回 void 的函数,返回其他类型则会报错。

3.2 有返回值

有返回值的函数必须使用第二种形式,返回值的类型必须与函数的返回类型相同,或者能隐式地转换成函数的返回类型。

不要返回局部对象的引用或指针,因为函数一旦完成,它所占用的内存空间也随之被释放掉,也意味着局部对象的引用或指针将引用一个不再存在的对象或指向不再有效的内存区域。

3.3 返回引用

调用一个返回引用的函数得到的是左值,其他的返回类型则是右值。因此可以让一个函数返回引用。特别地,可以为返回类型是非常量引用的函数的结果赋值(如果返回类型是常量引用就不能给调用的结果赋值):

char &function(string &str, int index)
{return str[index];		// 假定传入 function 函数的索引值都是有效的
}
int main()
{string s("a value"); 	// 等价于 string s = "a value";cout << s << endl;function(s, 0) = 'A';cout << s << endl;return 0;
}

注意到 function 前有个 &,表明函数返回的是 char & 类型,因此 function(s, 0) 返回的实际上是 string 对象 s 的0号位置上字符的引用,将其作为左值修改为 A,从而输出的结果如下:
在这里插入图片描述

3.4 列表初始化返回值

函数可以返回花括号包围的值的列表。类似于其他返回结果,此处的列表也用来对变量进行初始化。如果返回的列表是空,临时量就执行值初始化;否则,返回的值由函数的返回类型决定。如下:

vector<string> process()
{if (expression1)return {}; // 返回一个空 vector 对象else if (expression2)return {"1", "111"}; // 返回列表初始化的 vector 对象 elsereturn {"1", "111", "11111"};
}

(确实是没想到 vector 也能作为返回类型,但仔细一想想好像也没什么不可以的)如果函数返回的是内置类型,则花括号包围的列表最多包含一个值,而且该值所占空间不应该大于目标类型的空间。如果返回的是类类型,由类本身定义初始值如何使用。

3.5 递归

如果一个函数调用了它自身,不管这种调用是直接的还是间接的,都称该函数为递归函数。

3.6 返回数组指针

因为数组不能像 vector 那样拷贝,所以函数不能返回数组,但是可以返回数组的指针或引用。但直接定义一个返回数组指针或引用的函数很烦琐,最直接的方法就是使用类型别名:

typedef int arr[10];	// arr 是一个类型别名,它表示的类型是含有10个整数的数组
using arr = int[10];	// 等价声明
// 用别名来声明函数:function 返回一个指向含有10个整数的数组的指针
arr* function(int i);

上面第二条语句可以参考C++ 标准库类型学习笔记(一)(vector、string 篇)4.5 类型别名那一块。

3.6.1 声明一个返回数组指针的函数

要想在声明 function 时不使用类型别名,就必须牢记被定义的名字后面数组的维度:

int arr[10];	// arr 是一个含有10个整数的数组
int *p1[10];	// p1 是一个含有10个指针的数组
int (*p2)[10];	// p2 是一个指针,它指向含有10个整数的数组

返回数组指针的函数声明形式如下:

Type (*function(parameter_list))[dimension]

Type 表示元素的类型,function 是函数名,parameter_list 是形参列表,dimension 表示数组的大小。用一个具体的例子来解释:

int (*func(int i))[10];

可以按照由内到外的顺序来理解该声明:

  • func(int i) 表示调用 func 函数时需要一个 int 类型的实参。
  • (*func(int i)) 意味着可以对函数调用的结果执行解引用。
  • (*func(int i))[10] 表示解引用 func 的结果将得到一个大小为10的数组。
  • int (*func(int i))[10] 表示数组中的元素是 int 类型。

3.6.2 使用尾置返回类型

使用尾置返回类型可以简化上述 func 声明。任何函数都能使用尾置返回,但是这种形式对于返回类型比较复杂的函数最有效,比如返回类型是数组的指针或引用。尾置返回类型跟在形参列表后面并以一个 “->” 符号开头。然后在本应该出现返回类型的地方放一个 auto 表示函数真正的返回类型跟在形参列表之后。

// func 接受一个 int 类型的实参,返回一个指针,该指针指向含有10个整数的数组
auto func(int i) -> int(*)[10]

3.6.3 使用 decltype

如果知道函数返回的指针将指向哪个数组,就可以使用 decltype 关键字声明返回类型:

int odd[] = {1, 3, 5, 7, 9};
int even[] = {0, 2, 4, 6, 8};
// 返回一个指针,该指针指向含有5个整数的数组
decltype(odd) *arrPtr(int i)
{// 根据参数 i 的奇偶返回指向其中一个数组的指针return (i % 2) ? &odd : &even; // 返回一个指向数组的指针
}

decltype 并不负责把数组类型转换成对应的指针,所以 decltype 的结果是个数组,要想表示 arrPtr 返回指向数组的指针还必须在函数声明时加一个 * 符号。

练习

编写一个函数的声明,使其返回数组的引用并且该数组包含10个 string 对象。要求分别使用直接声明、类型别名、尾置返回类型以及 decltype。

我估计大多数读者都会疑惑,要求是数组(也就意味着不是 vector),还要求元素对象是 string,那该如何定义呢?我去百度查阅了才知道,原来 string 是可以定义成数组的…比如下面这种:

string s[] = {"111", "222", "333"};
cout << s[0] << ' ' << s[1] << ' ' << s[2] << endl;

输出结果如下:
在这里插入图片描述
所以函数声明可以写成如下四种形式:

// 直接声明
string (&func())[10]; { /*...*/ } // func() 表明调用函数不需要任何参数
// 类型别名
typedef string arr[10]; // arr 是一个类型别名,它表示的是含有10个 string 对象的数组
using arr = string[10]; // arr 的等价声明
arr &func();			// func 返回一个含有10个 string 对象的数组的引用
// 尾置返回类型
auto func() -> string (&)[10];
// decltype
string s[10]; 			// 定义一个 string 数组
decltype(s) &func();	// 返回一个含有10个 string 对象的数组的引用

4 函数重载

同一个作用域下,几个函数名字相同但形参列表不同,称之为重载函数。目的是减轻程序员起名字、记名字的负担。对于重载的函数来说,必须在形参的数量或者类型上有所不同。但有一种情况也不能算做重载函数,即2.1中提到的,实参初始化形参时会忽略掉顶层 const,一个拥有顶层 const 的形参无法和另一个没有顶层 const 形参区分开来:

int func(int i);
int func(const int i);	// 错误,重复声明了函数 int func(int i)
int func(int *i);
int func(int *const i);	// 错误,重复声明了 int func(int *i)

但是,如果形参是指针或者引用,那么通过区分其指向(引用)的是常量对象还是非常量对象就可以实现函数重载,因为此时的 const 是底层的:

int func(int*);			// 函数接受指向 int 型的指针作为形参
int func(const int*);	// 新函数,接受指向 const int* 型的指针作为形参
int func(int&);			// 新函数,接受 int 型的引用作为形参
int func(const int&);	// 新函数,接受 const int 型的引用作为形参

因为 const 不能转换成其他类型,所以只能把 const 对象传递给 const 形参;相反,因为非常量可以转换成 const,所以上面的四个函数都能作用于非常量对象或者指向非常量对象的指针。但是传递一个非常量对象或者指向非常量对象的指针时,编译器会优先选用非常量的版本。

5 特殊用途语言特性

5.1 默认实参

有时候,我们希望函数的某些形参在每次调用中都被赋予一个相同的值,这样我们在调用时就不需要每次都传值进去;但偶尔我们也希望自己重新传一个新的值进去计算,从而得到一个其他计算结果。此时就需要用到默认实参。比如我们想声明一个函数,它用来计算高度相等,半径不等的圆柱体的体积:每次计算,我们都只需传入圆的半径即可;也可以传入新的高度进行计算;或者如果需要更精确的结果,就传入精度更高的 π 值:

double cal_Volume(double radius, double hight = 10, double pi = 3.14);
// 普通调用:想使用默认形参,调用函数时省略它即可
cal_Volume(2);
// 传入新的高度进行计算
cal_Volume(2, 8)
// 需要更精确的结果时
cal_Volume(2, 10, 3.1415926);

有一点需要注意,一旦某个形参被赋予了默认值,在它右边的所有形参都必须有默认值。在给定的作用域中一个形参只能被赋予一次默认实参,函数的后续声明只能为之前那些没有默认值的形参添加默认实参,并且该形参右侧的所有形参都必须有默认值。

实参在初始化形参时是按照位置来的,如上面的 Cal_Volume 函数:如果我们不想改变高度,只想传入精度更高的 π,我们也必须填补上高度值,否则 Cal_Volume(2, 3.1415926) 的 3.1415926 会被用来初始化 hight。所以我们要尽量让不怎么使用默认值的形参出现在前面,让经常使用默认值的形参出现在后面。

5.2 内联函数和 constexpr 函数

5.2.1 内联函数

将函数指定为内联函数,通常就是将它在每个调用点上展开。将函数定义为内联函数需要在返回类型前加上 inline 关键字,比如:

inline int compare(int a, int b) // 函数返回较小值
{return a < b ? a : b;
}

那么下面的语句在调用 compare 函数,在编译过程中会展开成后者的形式:

cout << compare(1, 2) << endl;
cout << a < b ? a : b << endl;

这样做的目的是消除 compare 函数运行时的开销(涉及到中断的概念了)。一般来说,内联机制用于优化规模较小、流程直接、频繁调用的函数。而且很多编译器也不支持内联递归函数。

5.2.2 constexpr 函数

constexpr 函数是指能用于常量表达式的函数。定义 constexpr 函数要遵循几项约定:函数的返回类型及所有形参的类型都得是字面值类型,而且函数体中必须有且只有一条 return 语句:

常量表达式 是指值不会改变且在编译过程就能得到计算结果的表达式,比如字面值、用 const 初始化的对象等。

constexpr int func() { return 52; }
constexpr int a = func(); // 正确:a 是一个常量表达式

func 函数返回的是常量表达式,所以能用它来初始化 constexpr 类型的变量 foo。在执行初始化时,编译器会把对 constexpr 函数的调用替换成结果值,也就是说,constexpr 函数被隐式地指定为内联函数。当然也可允许 constexpr 函数的返回值并非一个常量:

constexpr int func(int cnt) { return 52 * cnt}

当调用 func 函数传入的实参是常量表达式时,比如 func(2),它的返回值也是常量表达式。但如果传入的是非常量表达式,比如 func(i),就不能够拿来初始化其他的常量表达式

编译器要想展开内联函数,仅仅有声明是不够的,还必须要有函数的定义。多次定义都必须一致,因此通常将内联函数和 constexpr 函数定义在头文件中。

6 函数指针

函数指针指向的是函数而非对象。函数指针指向某种特定类型,而函数的类型由它的返回类型形参类型共同决定:

// 声明一个 function 函数
bool function(const string &, const string &);
// 声明一个指向函数的指针
bool (*pf)(const string &, const string &);

从声明的名字开始观察,pf 前面有个 * 表明 pf 是指针;右侧的形参列表表明 pf 指向的是函数;左侧的 bool 表明返回类型是布尔值。因此,pf 是一个指向函数的指针,函数的参数是两个 const string 的引用,返回值是 bool 类型。

pf 两端的括号不能少,否则如下:

bool *pf(const string &, const string &);

此时是声明了一个名为 pf 的函数,该函数返回一个 bool 类型的指针。

6.1 使用函数指针

可以将函数名作为一个值使用,此时函数自动转换成指针,如下将函数 function 的地址赋给 pf:

// 取地址符可用可不用,前提是 pf 为指针
pf = function;
pf = &function;

可以直接使用指向函数的指针调用函数而无须解引用:

bool function(const string &, const string &) { ... };	// 定义一个 function 函数
bool (*pf)(const string &, const string &);				// 声明一个指向 function 函数的指针
bool b1 = pf("hello", "goodbye");						// 调用 function 函数,无须解引用
bool b2 = (*pf)("hello", "goodbye");					// 等价调用,解引用也可以
bool b3 = function("hello", "goodbye");					// 等价调用

因为指针指向的是函数,所以指向不同函数的指针间不存在什么转换规则。但是可以为指针赋一个 nullptr 或者值为0的整型常量表达式,表示该指针没有指向任何一个函数。

6.2 重载函数的指针

指针指向重载函数时,函数的类型一定要表示清楚:

// 定义两个重载函数
void function(int*) { ... }
void function(unsigned int) {...};void (*pf1)(unsigned int) = function; 	// 正确:定义了一个指向第二个函数的指针
void (*pf2)(int) = function; 			// 错误:形参列表不匹配
double (*pf3)(int*) = function; 		// 错误:返回类型不匹配

6.3 函数指针形参

函数的形参也可以是指向函数的指针,类似数组,此时的形参看起来是函数类型,实际上是当成指针来使用:

// 定义一个 function 函数
bool function(const string &, const string &) { ... };
// 第二个形参虽然是函数类型,但它会自动地转换成指向函数的指针
void test(const string &s1, bool pf(const string &, const string &));
// 等价的声明:显式地将形参定义成指向函数的指针
void test(const string &s1, bool (*pf)(const string &, const string &));
// 此时可以直接将函数当做实参传入,传入的函数名会自动转换成指针
test(s1, function);

使用类型别名可以简化形参的代码,如下所示:

// func1 和 func2 是函数类型
typedef bool func1(const string &, const string &);
typedef decltype(function) func2;						// 等价类型
using func3 = bool(const string &, const string &); 	// 等价类型

第一条语句实际上是给 bool (const string, const string &) 定义了一个别名 func1,用来指代任何参数是两个 const string 的引用,返回值是 bool 类型的函数。第二条语句是第一条语句的等价语句,decltype 返回的是上述的函数类型。要定义指向函数的指针的代码如下:

// pf1 和 pf2 是指向函数的指针
typedef bool(*pf1)(const string &, const string &);
typedef decltype(function) *pf2; 						// 等价类型
using pf3 = bool(*)(const string &, const string &);	// 等价类型

同理,第一条语句实际上是给 bool (*)(const string, const string &) 定义了一个别名 pf1,用来指代任何指向该函数类型的指针。第二条语句是第一条语句的等价语句,由于 decltype 返回的结果是函数类型,所以要在 pf2 前加上 * 才能得到指针。

因此可以用类型别名重新声明 test 函数:

void test(const string &, const string &, func1);
void test(const string &, const string &, pf2);

6.4 返回指向函数的指针

函数不能返回函数,但是能返回指向函数的指针。但是要将返回类型写成指针的形式,因为编译器不会将函数返回类型当成对应的指针。使用类型别名来返回函数的指针:

using F = int(int*, int);		// F 是函数类型
using PF = int(*)(int*, int);	// PF 是指针类型

必须显式地将返回类型指定为指针:

PF f1(int);		// 正确:PF 是指向函数的指针,f1 返回指向函数的指针
F f1(int);		// 错误:F 是函数类型,f1 不能返回一个函数
F *f1(int);		// 正确:显式地指定返回类型是指向函数的指针

也可用下面的形式直接声明 f1:

int (*f1(int))(int*, int);

由内向外进行理解:f1 有形参列表,所以 f1 是个函数;f1 前面有个 *,所以 f1 返回一个指针;进一步可以看到指针类型本身也包含形参列表,因此指针指向函数,函数的返回类型是 int。

也可以使用尾置返回类型声明一个返回函数指针的函数:

auto f1(int) -> int (*)(int*, int);

希望本篇博客能对你有所帮助,也希望看官能动动小手点个赞哟~~。

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASP.NET Core--依赖注入

文章目录依赖注入什么是依赖注入什么是依赖什么是注入依赖注入解决的问题.Net Core DI替换默认服务容器依赖注入 什么是依赖注入 什么是依赖 Rely类 public class Rely {public Task Test(string testMessage){Console.WriteLine(testMessage);return Task.FromResult(0);}…

【QT学习】如何绘制圆角窗口?

文章目录前言一、实现效果二、基础知识1.QBitmap类2.QPainter类3.setMask函数三、实现代码总结前言 在使用QT创建窗口时&#xff0c;所创建出来的默认窗口都是矩形的。当我们隐藏默认标题栏&#xff0c;想自己绘制自定义的标题栏时&#xff0c;就会发现矩形的窗口过于棱角分明。…

加深印象篇之Servlet

环境配置 需要配置web.xml文件,如图所示: userServlet:是指那个继承自HttpServlet的.java文件的名称 index.jsp:是指那个随意一个.jsp文件名称即可 要使用到Servlet相关类,需要提前将相关导包导入到pom.xml文件中 相关文件的编写 1、JDBCUtils.java文件(存储连接数据库的…

(附源码)计算机毕业设计ssm大数据学院图书管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

web前端面试题附答案016-怎么让顶部轮播图渲染的更快?

一、为什么强调轮播图&#xff1f; 很多时候我们强调用户体验&#xff0c;而这里更多时候我们更强调完美的首屏体验&#xff0c;而现在几乎每个网站顶部第一个大模块就是轮播图。轮播图占得区域最大&#xff0c;图片质量也更高&#xff0c;几乎一张图片的面积&#xff0c;体积就…

【C语言】结构体字节对齐

目录 前言 一、什么是字节对齐&#xff1f; 二、结构体字节对齐 三、#pragma pack()的使用 总结 结语 封面 前言 本教程可能会用到一点汇编的知识&#xff0c;看不懂没关系&#xff0c;知道是那个意思就行了。使用的工具是vs2010。 一、什么是字节对齐&#xff1f; 字节…

【易购管理系统】商品列表

我们来写一下商品管理界面 在Goods.vue中 <template><div><!-- 1.搜索区域 --><div class"header"></div><!-- 2.表格区域展示视图数据 --><div class"wrapper"></div><!-- 3.分页 --></div&g…

数据分析3-pandas

文章目录pandaspandas常用数据类型1.Series的创建pandas读取外部数据pandas读取数据库DataFrame基础字典列表排序索引loc与iloc字符串离散化数据的合并pandas pandas常用数据类型 Series一维数据&#xff0c;带标签数组 DataFrame 二维&#xff0c;Series容器 import pandas …

【ElasticSearch】(分组统计,自动补全,数据同步)

分组统计&#xff0c;自动补全&#xff0c;数据同步1.分组统计1-1.聚合为桶1-2.桶内度量2.RestAPI结果条件过滤数据同步安装MQ声明交换机、队列发送MQ消息接收MQ消息搭建集群修改系统配置集群状态监控1.分组统计 桶(bucket): 桶的作用&#xff0c;是按照某种方式对数据进行分…

关苏哲-洞察问题本质,解决工作难题

高效管理者的三大技能 问题界定的6个问题 1.你所需要解决的问题是什么&#xff1f; 2.你为什么需要解决这个问题&#xff1f; 3.你期待的理想结果是什么&#xff1f; 4.这个问题包括哪些子问题&#xff1f; 5.你曾经尝试过哪些解决方式&#xff1f;其他人呢&#xff1f; 6.这个…

(机器学习-深度学习快速入门)第二章数据分析基本工具正则表达式

文章目录一&#xff1a;说明二&#xff1a;正则表达式学习建议三&#xff1a;Python正则表达式简要说明&#xff08;1&#xff09;基本匹配&#xff08;2&#xff09;元字符①&#xff1a;.号②&#xff1a;字符集③&#xff1a;重复次数④&#xff1a;{}号⑤&#xff1a;(...)…

Spring(二)- 工厂高级

八&#xff1a;控制Spring工厂创建对象的次数 为什么要控制对象创建的次数 &#xff1f; 好处&#xff1a;节省不必要的内存浪费 &#xff01; 九&#xff1a;对象的生命周期 1.什么是对象的生命周期 指的是一个对象创建&#xff0c;存活&#xff0c;消亡的一个完整过程 2.…

基于朴素贝叶斯算法对肿瘤类别分类

目录 朴素贝叶斯算法​编辑 朴素贝叶斯的三种方式 实战——肿瘤类别的分类 朴素贝叶斯算法 贝叶斯定理 贝叶斯定理&#xff08;Bayes Theorem&#xff09;也称贝叶斯公式&#xff0c;是关于随机 事件的条件概率的定理 定理内容&#xff1a; 如果随机事件A1 ,A2 ,...,An构成…

【177】Java利用JNI调用C++编写的DLL,连接海康人脸抓拍机,实现人脸库全量更新。

C开发环境&#xff1a;Visual Studio 2022、windows10 Java开发环境&#xff1a;Java8、idea、windows10 这个DLL功能&#xff0c;是输入一个设备IP&#xff0c;删除设备中的所有以前的人员资料&#xff0c;然后用文件夹中XML和图片的新人脸库资料上传到设备的人脸库中。相当于…

【MySql】常用语法及例题

文章目录字符串处理函数/正则rlikegroup_concat组合查询 & 指定选取union all字符串处理函数/正则 rlike 在MySQL中&#xff0c;RLIKE运算符用于确定字符串是否匹配正则表达式。它是REGEXP_LIKE()的同义词。 如果字符串与提供的正则表达式匹配&#xff0c;则结果为1&…

【网安神器篇】——WPScan漏洞扫描工具

作者名&#xff1a;Demo不是emo 主页面链接&#xff1a;主页传送门创作初心&#xff1a;对于计算机的学习者来说&#xff0c;初期的学习无疑是最迷茫和难以坚持的&#xff0c;中后期主要是经验和能力的提高&#xff0c;我也刚接触计算机1年&#xff0c;也在不断的探索&#xf…

理解递归与循环

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

Matlab论文插图绘制模板第52期—三维分簇散点图(Swarmchart3)

在之前的文章中&#xff0c;分享了Matlab分簇散点图的绘制模板&#xff1a; 抖动控制的分簇散点图&#xff1a; 这一次&#xff0c;再来分享一下三维分簇散点图。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;Matlab论文插图绘制模板系列&#xff0c;旨在降低大家使用…

Oracle SQL 执行计划

解释计划 语句EXPLAIN PLAN 用来显示优化器为SQL语句选择的执行计划。将估计的信息称为解释计划输出&#xff0c;把实际信息称为执行计划输出。以此区分实际的和预期的执行计划。 使用解释计划 当使用EXPLAIN来为查询生成预期的执行计划时&#xff0c;输出将包括以下几种&…