C++の函数

Wesley13
• 阅读 561

题图: NoCopy

字数:1747   |   读完仅需2分钟


C++の函数

续停更三天,让你们久等了,今天继续。今天我们开始了解C++中的函数的概念。

说到函数,我们应该比较清楚了,不论哪一门语言都有这个概念的,其实本质上就是讲我们之前介绍的语句,表达式等封装起来,形成一个功能单元。在C/C++中它也是程序执行的最小单元,我们新建一个工程,如果想要编译通过的话,必须要有一个主函数main。

但是在一个解释型语言,就不必要了,想js, shell,python等。以后,我们介绍的Go语言,也是编译型语言,也是需要main函数的,只不过形式不同而已。

函数的定义

首先,我们先说一下函数的定义方法,函数包括返回值,函数名,以及参数列表,返回值可以具有实际意义,也可以为void,参数列表呢,可以有,也可以没有。这个C/C++中没什么区别。下面举个例子怎么定义一个函数:

static BrewFunction GetBrewFunction(const caffe::string& name) {  if (g_brew_map.count(name)) {    return g_brew_map[name];  } else {    LOG(ERROR) << "Available caffe actions:";    for (BrewMap::iterator it = g_brew_map.begin();         it != g_brew_map.end(); ++it) {      LOG(ERROR) << "\t" << it->first;    }    LOG(FATAL) << "Unknown action: " << name;    return NULL;  // not reachable, just to suppress old compiler warnings.  }}

上面就是一个函数的例子,BrewFunction是返回值,GetBrewFunction是函数名,const caffe::string& name 是函数的参数列表。其实这部分代码是我从深度学习框架caffe中截取的一点。

我决定以后文章中的示例代码,我就从一些经典的开源项目中寻找吧,这样的话如果我们以后用到的话,可以更快熟悉,如果不用,也没太大关系,建议大家在学习完基础教程后,多去阅读一下开源代码,这样,我们的技能可以提升得更快。

参数列表的使用

我们在定义函数时,经常需要往一个函数里面传递参数。比如下面的代码:

void Blob<Dtype>::Reshape(const BlobShape& shape) {  CHECK_LE(shape.dim_size(), kMaxBlobAxes);  vector<int> shape_vec(shape.dim_size());  for (int i = 0; i < shape.dim_size(); ++i) {    shape_vec[i] = shape.dim(i);  }  Reshape(shape_vec);}

我要实现一个改变数据形状的函数,我就要传递一个BlobShape类型的参数, 可以看到上面这个参数shape也是一个BlobShape引用。我们把这成为传引用调用。如果是下面这样的,仅仅传一个值的话,我们称为“传值调用”。

void Blob<Dtype>::Reshape(const BlobShape shape) {  CHECK_LE(shape.dim_size(), kMaxBlobAxes);  vector<int> shape_vec(shape.dim_size());  for (int i = 0; i < shape.dim_size(); ++i) {    shape_vec[i] = shape.dim(i);  }  Reshape(shape_vec);}

除了传引用,传值以外,我们的参数列表还可以传递指针,就是把一个对象或变量的地址传进去,传递指针可以实现和传递引用同样的功能,就是希望通过函数改变参数的值,然后能把这个值传出。这种用法很多很多。

void DataTransformer<Dtype>::Transform(const vector<cv::Mat> & mat_vector,                                       Blob<Dtype>* transformed_blob) {  const int mat_num = mat_vector.size();  const int num = transformed_blob->num();  const int channels = transformed_blob->channels();  const int height = transformed_blob->height();  const int width = transformed_blob->width();  CHECK_GT(mat_num, 0) << "There is no MAT to add";  CHECK_EQ(mat_num, num) <<    "The size of mat_vector must be equals to transformed_blob->num()";  Blob<Dtype> uni_blob(1, channels, height, width);  for (int item_id = 0; item_id < mat_num; ++item_id) {    int offset = transformed_blob->offset(item_id);    uni_blob.set_cpu_data(transformed_blob->mutable_cpu_data() + offset);    Transform(mat_vector[item_id], &uni_blob);  }}

看上面的transformed_blob,就是Blob<Dtype>类型的指针,我们可以在函数外面定义一个这个类型的变量,然后把它作为参数传入Transform函数,然后,我们就可以在函数中改变参数的值,最后把它传出去。

那么,从上面的例子中我们看到,函数中出现了const这个限定符,这里有什么用呢?这里const就是我们之前讲的,限定,不可更改。

就是说如果我们不打算在函数中修改传入的变量的话,最好把它用const加以限定,当然这不是必须的,这只是一个C++程序员的基本修养,一种编程习惯。当然,这也是非常有益处的。

比如,你要开发一个库给第三方调用,你不希望某个输入参数在代码运行时被更改,那么就应该使用const,强制限定。

除此以外,如果我们的参数比较大的话,也建议使用引用形参传递给参数,因为引用没有实体,是原输入数据的别名,不对数据进行拷贝,因此有更高的效率。

main函数获取命令行参数

很多情况下,我们会用到main函数获取命令行参数,那么这是怎么实现的呢?

我们先来看一下main函数的完整定义:

int main(int argc, char * argv[]){    ...}

上面的代码中,argc就是表示参数列表的个数,argv就是参数列表数组,假设我有一个test_func可执行文件,我在命令行执行下面的命令:

test_func arg1 arg2 arg3 arg4 arg5

那么我们就可以在函数中读到argc的值为5,参数列表中的值分别为:

argv[0] = arg1argv[1] = arg2argv[2] = arg3argv[3] = arg4argv[4] = arg5

明天继续说C++中的函数

C++の函数

本文分享自微信公众号 - leoay(leoay_Do)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
3年前
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解2016年09月02日00:00:36 \牧野(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fme.csdn.net%2Fdcrmg) 阅读数:59593
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
3年前
Github标星5300+,专门为程序员开发文档开源管理系统,我粉了
!(https://oscimg.oschina.net/oscnet/a11909a041dac65b1a36b2ae8b9bcc5c432.jpg)码农那点事儿关注我们,一起学习进步!(https://oscimg.oschina.net/oscnet/f4cce1b7389cb00baaab228e455da78d0
Stella981 Stella981
3年前
HIVE 时间操作函数
日期函数UNIX时间戳转日期函数: from\_unixtime语法:   from\_unixtime(bigint unixtime\, string format\)返回值: string说明: 转化UNIX时间戳(从19700101 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式举例:hive   selec
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Nginx反向代理upstream模块介绍
!(https://oscimg.oschina.net/oscnet/1e67c46e359a4d6c8f36b590a372961f.gif)!(https://oscimg.oschina.net/oscnet/819eda5e7de54c23b54b04cfc00d3206.jpg)1.Nginx反
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这