前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++の函数

C++の函数

作者头像
leoay
发布2020-01-14 16:26:58
4990
发布2020-01-14 16:26:58
举报
文章被收录于专栏:leoayleoay

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] = arg1
argv[1] = arg2
argv[2] = arg3
argv[3] = arg4
argv[4] = arg5

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 leoay 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档