小古银的官方网站(完整教程):http://www.xiaoguyin.com/
C++入门教程视频:https://www.bilibili.com/video/av20868986/
目录
函数类型
函数实际上也是一个值,也就是说,函数可以用变量来保存,而这个变量的数据类型是std::function
。std::function
是一个类,它在functional
标准库中。
假设要保存函数int myabs(int num);
,那么就需要使用数据类型std::fuction<int(int)>
,即在std::function
的<>
里面填返回值(参数类型)
,完整的赋值语句是std::function<int(int)> myfunc = myabs;
。当然也可以用auto
来声明变量:auto myfunc = myabs;
。
简短的示例:
int myabs(int num); // 声明函数
std::function<int(int)> myfunc = myabs; // 用变量myfunc保存myabs函数
myabs(-1024); // 函数的调用
myfunc(-2333); // 这时候myfunc也是函数,调用方法和上面myabs一样
以下讲解函数类型的用途,即为什么要用函数类型。先看几个问题。
写一个函数,函数声明是这样的:unsigned int count_gu(std::u32string text);
;功能是用来统计指定字符串中有多少个古
字;函数有一个参数text
,就是需要被统计的字符串;返回类型是unsigned int
,代表字符串中有多少个古
字。
基础示例 1
#include <iostream> // std::cout std::endl
#include <string> // std::u32string
// 以下是统计函数的使用说明
// 功能: 统计指定字符串中有多少个古字
// 参数: 需要被统计的字符串
// 返回值: 字符串中古字的数量
unsigned int count_gu(std::u32string text);
int main(void)
{
// 统计字符串中一共有多少个古字
auto numofgu = count_gu(U"小古银小古银我是美美哒小古银");
std::cout << R"raw(字符串有多少个古字:)raw" << numofgu << std::endl;
return 0;
}
unsigned int count_gu(std::u32string text)
{
// 遍历字符串中所有字符, 如果符合条件则统计
unsigned int count = 0; // 用来保存统计数量
for (auto ch : text)
{
if (ch == U'古')
{
++count;
}
}
// 返回统计数量
return count;
}
输出结果:
字符串有多少个古字:3
再写一个函数,函数声明是这样的:unsigned int count_guyin(std::u32string text);
;功能是用来统计古
字和银
字在指定字符串中一共有多少个;函数有一个参数text
,就是需要被统计的字符串;返回类型是unsigned int
,代表字符串中一共有多少个古
字和银
字。
基础示例 2
#include <iostream> // std::cout std::endl
#include <string> // std::u32string
// 以下是统计函数的使用说明
// 功能: 统计指定字符串中一共有多少个古字和银字
// 参数: 需要被统计的字符串
// 返回值: 字符串中古字和银字的数量
unsigned int count_guyin(std::u32string text);
int main(void)
{
// 统计字符串中一共有多少个古字
auto numofguyin = count_guyin(U"小古银小古银我是美美哒小古银");
std::cout << R"raw(字符串有多少个古字和银字:)raw" << numofguyin << std::endl;
return 0;
}
unsigned int count_guyin(std::u32string text)
{
// 遍历字符串中所有字符, 如果符合条件则统计
unsigned int count = 0; // 用来保存统计数量
for (auto ch : text)
{
if (ch == U'古' || ch == U'银')
{
++count;
}
}
// 返回统计数量
return count;
}
输出结果:
字符串有多少个古字和银字:6
基础讲解 2
可以看出两份代码中,unsigned int count_gu(std::u32string text);
和unsigned int count_guyin(std::u32string text);
的函数定义除了if
的判断不同,其他部分是一模一样的。既然两个函数的功能都是统计,而定义基本都是一样,那么就要考虑把它们统一成一个函数。
之前是因为值不同,所以可以用变量来作为函数参数来保存不同的值;而现在是不同的语句,可以考虑将语句写在函数里。上面说明过,函数也是一个值,不同的函数是不同的值,既然是值就可以用变量来保存。那么就可以将判断语句放到函数里,然后通过形式参数传到统计函数里。这时候就要考虑,这个用来判断的函数怎样写,同样也要考虑参数的类型是什么。
这个判断函数是用来放判断条件的。之前说过,判断就是一个运算,而运算结果是bool
,那么这个判断函数的返回值就是bool
。而需要判断的就是一个字符,那么形式参数的类型就是char32_t
。这样,我们自己定义函数名isgu
用来判断字符是不是古
字,定义函数名isguyin
用来判断字符是不是古
字或者银
字。这两个函数的函数声明如下:
bool isgu(char32_t ch);
bool isguyin(char32_t ch);
由于它们的返回值和参数类型都是一样的,那么它们都可以用类型std::function<bool(char32_t)>
声明的变量来保存,例子如下:
std::function<bool(char32_t)> isgufunc = isgu;
std::function<bool(char32_t)> isguyinfunc = isguyin;
所以可以用数据类型std::function<bool(char32_t)>
来作为统计函数的参数的数据类型。
基础示例 3
那么将两个函数统一成一个函数就可以这样写:
#include <iostream> // std::cout std::endl
#include <functional> // std::function
#include <string> // std::u32string
// 以下是统计函数的使用说明
// 功能: 统计函数
// 参数: 需要被统计的字符串
// 参数: 统计函数需要的判断函数, 统计函数将会向判断函数传入每一个字符,
// 然后统计函数会根据判断函数的返回值进行统计, 如果判断函数返回
// true, 统计函数则会处理; 如果判断函数返回false, 统计函数则忽略
// 返回值: 统计判断函数返回true的数量
unsigned int count_if(std::u32string text, std::function<bool(char32_t)> pred);
// 判断指定的UTF-32字符是不是古字
// 参数: 需要判断的字符
// 返回值: 如果指定字符是古字则返回true; 反之返回false
bool isgu(char32_t ch);
// 判断指定的UTF-32字符是不是古字或者银字
// 参数: 需要判断的字符
// 返回值: 如果指定字符是古字或者银字则返回true; 反之返回false
bool isguyin(char32_t ch);
int main(void)
{
// 统计字符串中一共有多少个古字
auto numofgu = count_if(U"小古银小古银我是美美哒小古银", isgu);
// 统计字符串中一共有多少个古银这两个字
auto numofguyin = count_if(U"小古银小古银我是美美哒小古银", isguyin);
// 输出
std::cout << R"raw(字符串有多少个古字:)raw" << numofgu << std::endl;
std::cout << R"raw(字符串有多少个古字和银字:)raw" << numofguyin << std::endl;
return 0;
}
unsigned int count_if(std::u32string text, std::function<bool(char32_t)> pred)
{
// 遍历字符串中所有字符, 如果符合条件则统计
unsigned int count = 0; // 用来保存统计数量
for (auto ch : text)
{
if (pred(ch))
{
++count;
}
}
// 返回统计数量
return count;
}
bool isgu(char32_t ch)
{
return ch == U'古';
}
bool isguyin(char32_t ch)
{
return ch == U'古' || ch == U'银';
}
输出结果:
字符串有多少个古字:3
字符串有多少个古字和银字:6
基础讲解 3
先从设计函数的思维去看:函数count_if()
用来统计符合条件的字符数量。然而函数count_if()
只负责统计,它并不知道什么样的条件是符合的,他就把这个任务交给参数pred
去负责,把每只字符都给pred()
函数判断一下,只要pred()
函数返回true
,函数count_if()
就认为是符合条件而去统计。那么函数count_if()
就可以专心负责统计而不用理会细节。而参数pred
就身负着判断是否符合条件的重任,它化身成为类型是std::function<bool(char32_t)>
的函数,只为了完成判断每种不同条件的光荣使命。
再从调用函数的角度去玩:就是统计函数的使用说明。函数count_if()
的第一个参数是需要被统计的字符串,而第二个参数是给函数count_if()
判断用的,应该由调用者来定义什么字符是需要被统计的。我们需要统计有多少个古
字,还有需要统计一共有多少个古
字和银
字,所以就写了两个判断函数isgu
和isguyin
,供统计函数判断使用。
补充知识(了解即可)
std::function
从C++11开始加入。