C++学习笔记:函数

1、函数基础

  典型的函数定义包括:返回类型、函数名、由0个或多个形参组成的列表以及函数体。

2、参数传递

  形参初始化的机理和变量初始化一样。

  有两种方式:引用传递和值传递

2.1 传值参数

  当形参是非引用类型时,形参初始化和变量初始化一样,将实参的值拷贝给形参。

指针形参

  当执行指针拷贝操作时,拷贝的是指针的值,拷贝之后,两个指针是不同的指针。但通过指针可以修改它所指的对象。

2.2 传引用参数

使用引用避免拷贝

  拷贝大的类类型对象或者容器对象比较低效,甚至有的类类型根本就不支持拷贝操作。当某种类型不支持拷贝操作时,函数只能通过引用形参访问该类型的对象。

使用引用形参返回额外信息

2.3 const形参和实参

  当用实参初始化const形参时会忽略顶层const。因此,当形参有顶层const时,传给它常量对象或者非常量对象都是可以的。

1

2

3

void fun1(const int i){.......}

void fun2(int i){.....}

  上述两个函数不能算是重载,两个函数是一样的,程序会报错,fun2重复定义了fun1.

指针或引用形参与const

  可以使用非常量初始化一个底层const对象,但是反过来不行。同时一个普通的引用必须用同类型的对象初始化。

图1

尽量使用常量引用2.4 数组形参数组有两个重要的特性:不允许拷贝使用数组时会转换成指针尽管不能以值传递的方式传递数组,但是可以将形参写成类似数组的形式12345void print(const int*);void print(const int[]);void print(const int[10]); 以上三种形式的声明等价NOTE:当函数不需要对数组元素执行写操作的时候,数组形参应该是指向const的指针。只有当函数确实要改变元素值的时候,才把形参定义成指向非常量的指针。当数组作为函数形参时,因此应该提供一些额外信息来确定数组的确切尺寸,管理数组形参有三种常用的技术:使用标记指定数组长度  要求数组本身包含一个结束标记。例如C风格字符串以空字符结尾。使用标准库规范  传递指向数组首元素和尾元素的指针。1234567void print(const int *beg,const int *end){ while(beg!=end) { cout<<*beg++

print(begin(arr),end(arr));显式传递一个表示数组大小的形参  专门定义一个表示数组大小的形参。12345void print(const int ia[], size_t size); int j[]={0,1}; print(j, end(j)-begin(j));数组引用形参  形参可以是数组的引用,此时,引用形参绑定到对应的实参上,也就是绑定到数组上。12345678void print(int (&arr)[10]){    for(auto elem:arr)    {          cout<

图2

lnitializer_list和vector一样都是模板类型,不同的是initializer_list对象中的元素永远是常量值,不能改变。12345678void error_msg(initializer_listls){ for (auto beg = ls.begin(); beg != ls.end(); ++beg) { cout << *beg << " "; } cout << endl;}error_msg({ "hello" });error_msg({ "hello!", "world!!" });  //注意值的传递要放在花括号里省略符形参  省略符形参是为了便于C++程序访问某些特殊的C代码而设置的。通常,省略符形参不应用于其他目的。省略符形参只能出现在形参列表的最后一个位置。实参类型不同,使用可变参数模板3、返回类型和return语句3.1 无返回值函数  返回类型是void类型的函数3.2 有返回值函数值是如何被返回的  返回一个值的方式和初始化一个变量或形参的方式完全一样:返回的值用于初始化调用点的一个临时量,该临时量就是函数调用的结果。 不要返回局部对象的引用或指针返回类类型的函数和调用运算符1auto sz=getstring().size(); //getstring返回的string对象再调用size函数 引用返回左值调用一个返回引用的函数得到左值,其他返回类型得到右值。 列表初始化返回值函数可以返回花括号包围的值的列表。1234vectorprocess(){ return {"ni","hao"};} 递归如果一个函数调用了它自身,不管这种调用是直接还是间接的,都称该函数为递归函数。1234567int factorial(int val){ if(val>1) return factorial(val-1)*val; return 1;}求1x2x3x4...... 3.3 返回数组指针因为数组不能被拷贝,所以函数不能返回数组。不过,函数可以返回数组的指针或引用。最直接的方法是使用类型别名12typedef int arrT[10];using arrT=int[10]; 声明一个返回数组指针的函数123int arr[10]; //arr是一个含有10个整数的数组int *p1[10]; //p1是一个含有10个整型指针的数组int (*p2)[10]=&arr; //p2是一个指针,其指向一个有10个整数的数组 如果要定义一个返回数组指针的函数,则数组的维度必须跟在函数名字之后,并且函数的形参列表应该先于数组的维度。1int (*func(int a,int b))[10]; 此函数返回的是一个指向有10个整数数组的指针。 使用尾置返回类型任何函数的定义都能使用尾置返回,但是这种形式对于返回类型比较复杂的函数最有效,比如返回类型是数组的指针或引用。尾置返回类型跟在形参列表后面并以一个->符号开头。为了表示函数真正的返回类型跟在形参列表之后,我们在本应该出现返回类型的地方放置一个auto。1auto func(int i)->int (*)[10]; 使用decltype4、函数重载如果同一作用域内的几个函数名字相同但形参列表不同,称为函数重载。注意必须是形参列表不同,仅仅只是返回类型不同不可以称为重载。重载和const形参顶层const不影响传入函数的对象。一个拥有顶层const的形参无法和另一个没有顶层const的形参区分开来。12345int f1(int i);int f1(const int i); //不构成重载,重复声明了f1 int f2(int *i);int f2(int *const i); //不构成重载,重复声明了f2但底层const不同,可以构成重载12345int f1(int &i);int f1(const int &i); //重载,新函数 int f2(int *i);int f2(const int *i); //重载,新函数NOTE:最好只重载那些确实非常相似的操作。const_cast和重载const_cast在重载函数的情景中最有用。1234567891011const string &shorterString(const string &s1, const string &s2){ return s1.size() <= s2.size() ? s1 : s2;} string &shorterString(string &s1, string &s2){ auto &r = shorterString(const_cast(s1), const_cast(s2)); return const_cast(r);

}

4.1 重载与作用域

如果在内层作用域中声明名字,它将隐藏外层作用域中声明的同名实体。

1

2

3

4

5

6

7

8

9

10

void func()

}

int main()

    int func=0;

    func();    //错误,此时func是int类型的变量,不是函数,隐藏了外层的函数定义

    return 0;

}

5、特殊用途语言特性

  默认实参、内联函数和constexpr函数。

5.1 默认实参

一旦某个形参被赋予了默认值,它后面的所有形参都必须有默认值。

1

string  screen(int i=10, int a=1, stirng s=" ");

使用默认实参调用函数

在调用函数的时候省略该实参就可以。

默认实参声明

在给定的作用域中一个形参只能被赋予一次默认实参。

默认实参初始值

局部变量不能作为默认实参。除此之外,只要表达式的类型能转换成形参所需的类型,该表达式就能作为默认实参。

5.2 内联函数和constexpr函数

调用函数一般比求等价表达式的值要慢一些。

内联函数可避免函数调用的开销

在函数的返回类型前面加上关键字inline。

一般来说,内联机制用于优化规模较小、流程直接、频繁调用的函数。

constexpr函数

constexpr函数是指能用于常量表达式的函数。

定义constexpr函数要遵循:函数的返回类型及所有形参的类型都得是字面值类型,而且函数体中必须有且只有一条return语句。

1

2

3

4

5

6

constexpr int new_sz()

    return 42;

}

constexpr int foo=new_sz();    //foo是一个常量表达式

为了能在编译过程中随时展开,constexpr函数被隐式地指定为内联函数。

NOTE:constexpr函数不一定返回常量表达式。

把内联函数和constexpr函数放在头文件内

和其他函数不一样,内联函数和constexpr函数可以在程序中多次定义。不过,对于某个给定的内联函数或者constexpr函数来说,它的多个定义必须完全一致。因此,内联函数和constexpr函数通常定义在头文件中。

5.3 调试帮助

两项预处理功能:assert和NDEBUG

assert预处理宏

assert宏常用于检查“不能发生”的条件。

1

assert(expr);

如果expr为假,assert输出信息并终止程序执行,如果为真,assert什么也不做。

NDEBUG预处理变量

assert的行为依赖于一个名为NDEBUG的预处理变量的状态。如果定义了NDEBUG,则assert什么也不做,默认情况下没有定义NDEBUG。

可以使用#define语句定义NDEBUG,从而关闭调试状态。

6、函数指针

函数指针指向的是函数而非对象。和其他指针一样,函数指针指向某种特定类型。函数的类型由它的返回类型和形参类型共同决定,与函数名无关。

1

int func(int a, string s);

该函数的类型是int(int , string).要想声明一个可以指向该函数的指针,只需要用指针替换函数名即可。

1

int (*p)(int ,string )  //未初始化

NOTE:*p的括号必须加上

使用函数指针

当把函数名作为一个值使用时,该函数自动地转换成指针。

1

int (*p)(int ,string )=func;

可以使用函数指针直接调用该函数,而不需要解引用该指针。

指向不同函数类型的指针之间不存在相互转换,可以给函数指针赋值nullptr和0,表示指针没指向任何一个函数。

重载函数的指针

如果定义了指向重载函数的指针,编译器通过指针类型决定选用哪个函数,指针类型必须与重载函数中的某一个精确匹配。

函数指针形参

和数组类似,虽然不能定义函数类型的形参,但是形参可以是指向函数的指针。可以直接把函数作为实参使用,此时它会自动转换成指针。

图3

返回指向函数的指针

将auto和decltype用于函数指针类型

注意将decltype用于函数名时,返回的是函数类型,而非指针类型,如果要表示函数指针,需要自己加上*。

有想要学习视频的可以加一下学习qun710520381 学习编码:久伴

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容

  • 函数基础 函数定义:返回类型、函数名、0个或多个形参组成的列表、函数体。形参以逗号隔开。形参列表位于一对圆括号内。...
    HungweeHou阅读 263评论 0 0
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 9,487评论 1 51
  • 1.C和C++的区别?C++的特性?面向对象编程的好处? 答:c++在c的基础上增添类,C是一个结构化语言,它的重...
    杰伦哎呦哎呦阅读 9,426评论 0 45
  • 今日跑步:5km平均配速:605平均心率:147平均步频:172天气:阴,26℃感受:很好 各种关于跑步的书里面,...
    ahb阅读 317评论 0 2
  • 做计划的方式有很多种,但我个人经过尝试,最偏爱的还是按照时间轴来做计划。 以前在做计划时也尝试过很多不同的方式,比...
    冯毓阅读 231评论 0 0