函数---C++ 基础
来源:互联网 发布:直销管理系统源码 编辑:程序博客网 时间:2024/05/16 19:23
前言
刚看了《桃子的博客》,关于个人阶段性学习的总结。深感自己要从事后端开发需要学习更多的知识。语言仅仅是基础的基础。还需要对算法以及操作系统、网络、分布式有深入的学习。前方的路还很长,现在必须要先打起精神,先把这个语言过关计划搞定。所有的坚持一定会有收获。
函数是编程语言中的重要一环,实际是一个代码块。有入口和出口。本文只提出一些需要注意的东西。
1.局部对象
函数构成一个新的作用域,在函数内部定义的变量叫局部变量,会隐藏外层作用域同名的声明。
局部变量的生命周期依赖于定义的方式。
- 自动对象
自动对象是函数中普通的变量,随着函数执行而被创建,随函数退出而被销毁。另外,函数中定义的普通变量如果有初始值,则使用初始值初始化,否则默认初始化,这时候是未定义的的值。类类型默认初始化是自己控制的。
- 局部静态对象
生命周期和程序生命周期一致,证明局部静态对象的存储位置是静态区。局部静态对象使用static 来定义,函数第一次被执行时初始化。
2.分离式编译
c++支持分离式编译,最好的方式是在头文件中写函数声明,在源文件中写函数定义。需要在源文件中引入头文件。
3.参数传递
- 传值
- 传引用
- 传指针
具体的概念就不说了,很清晰。提一点,传引用可以避免拷贝,如果函数中不需要改变引用变量,最设置成常量引用。另外,传引用还可以作为一个返回值来使用。因为C++函数只能返回一个值,当然也可以打包成一个类型然后返回,但是这样比较麻烦。
- const形参和实参
记住一点,实参初始化是忽略顶层const的,或者说形参的顶层const被忽略掉了。
void fcn(const int i) {}void fcn(int i) {} // 错误:重复定义函数,实际我的编译器是能编译通过的,而且每次调用的都是第一个,这个可能和编译器的实现相关
另外,按引用传递还需要注意引用的初始化,字面值常量需要顶层const。
void fcn(string &s){}fcn("hello"); // 错误:字面值常量,需要const
- 数组形参
数组形参需要好好复习一下,之前总是出错。
首先,数组有两个特点,1.不允许拷贝数组;2. 使用数组时(通常)会转换成指针。
于是,我们知道数组作为形参,不能值传递,实际传递的是数组的头指针
// 三者都是等价的void print(const int *);void print(const int[]);void print(const int[10]);
因此,函数体内遍历数组,需要知道数组大小,避免越界。三种方式解决
- 设置哨兵(字符数组末尾的空字符)
- 传递头指针和尾指针(标准库规范)
- 显示传递一个数组大小的形参
数组引用形参(限制死了形参数组的大小,可用性不好)
void print(int (&arr)[10]) { for (auto elem : arr) cout << elem;} // 这样传递的是数组的引用,维度是类型的一部分
- 传递多维数组
实际传递的是数组的指针,不能忽略第二维或者第三维的大小。
void print(int (*matrix)[10], int rowsize) {}void print(int matrix[][10], int rowsize) {}// 等价,但是传递的是第一行的数组的指针,还需要传递行数大小
- 关于值是如何被返回的
函数调用会产生一个临时量,返回值用于初始化这个临时量。
如果返回的是非引用,返回值会被拷贝到调用点。
注意:
不要返回局部对象的引用或指针
如果是返回引用,不要返回字面值,字面值在函数里是一个局部临时量。
返回引用,返回的是左值,要注意是不是常量引用
- c++ 11 支持返回初始化列表
返回的列表初始化调用点的临时量。
vector<int> process() { return {1, 2};}
4.函数重载
函数名字相同,而形参列表不同,称为重载(overload)
因此,注意返回值不同,两个函数的定义还是一样的,这样就会造成编译器错误。
- 重载与const
顶层const忽略,因此无法区分
void lookup(int i);void lookup(const int i); // 重复声明void lookup(int *i);void lookup(int *const i); // 重复声明void lookup(int &i);void lookup(const int &i); // 重载void lookup(int *i);void lookup(const int *i); // 重载
利用 const_cast
能够显示转换常量和非常量
5.默认实参
- 一旦设置了默认实参,后面的都需要有默认值
- 默认实参只能设置一次,因此,多次声明要注意不能重复设置实参
6.调试帮助
开发的时候,需要编写某些调试代码,等到发布时需要屏蔽调试代码。这时候需要一些调试方法。
用到两项预处理器功能:assert和NDEBUG。
assert需要头文件 cassert。NDEBUG是一个宏名字,如果定义了NDEBUG,则assert() 啥也不干。否则,assert测试表达式是否为真。
另外,还有很多预处理器阶段进行宏替换的名字
__func__
当前函数名字__FILE__
当前文件名__LINE__
当前行号__TIME__
文件编译时间__DATE__
文件编译日期
7.函数指针
函数名作为一个值使用时,该函数自动转换为一个指针。
using F = int (int *, int);using PF = int (*)(int *, int);// 等价于typedef int F(int *, int);typedef int (*PF)(int *, int);auto f1(int) -> int (*)(int *, int) // 尾指返回类型的方式decltype(F) *getFcn(int); // decltype根据表达式推测类型,返回的是函数,所以这里还需要加上*
注意:
decltype 可以用于推测表达式的类型,如果使用的是函数调用,那推测的是返回类型,而不是函数类型
对一个函数名进行操作,decltype(func) 返回的是函数,并不是函数指针
- C 基础 (函数)
- C基础:函数
- C语言基础 函数
- C语言基础 函数
- C函数指针基础
- 【基础C&C++】内存函数
- C语言基础函数(一)
- C语言基础 函数指针
- C++---基础篇(函数)
- C语言函数指针基础
- C语言函数指针基础
- C语言函数指针基础
- C语言函数指针基础
- C语言函数指针基础
- C语言函数指针基础
- C语言函数指针基础
- C语言函数指针基础
- C语言函数指针基础
- C/C++读写二进制文件
- pl/sql developer job创建
- iOS
- 练习74
- Java的volatile变量
- 函数---C++ 基础
- java中网络编程------UDP协议(实现步骤)DatagramSocket对象
- AtCoder AtCoder Beginner Contest 063 D
- 算法竞赛入门经典-习题3-6 纵横字谜的答案(Crossword Answers, ACM/ICPC World Finals 1994,UVa232)
- Android audio打开Microphone流程(App--->driver)
- 16.java语言基础-算术运算符
- 性能优化的三个维度
- 练习75
- jquery选择器总结