《C++ Primer》Chapt 7 Functions
这是看第2遍,看得比较仔细,笔记如下:
函数调用在编译期,会检查实参与实参是否匹配。
注意,其中可能的话,会发生隐式类型转换,编译器只是给出警告
缺省情况是按值传递,实参的值拷贝到参数的存储区。函数处理的是实参的拷贝
按地址传递:引用和指针参数
1. 函数需要改变实参
2. 向函数传递大型对象时的效率考虑
3. 需要函数返回额外的结果
当需要2时,却不希望1发生,一个解决是:将参数声明为const引用类型
另外,如果用指针参数,需要在解引用前判断指针是否为NULL
数组总是按指针传递
数组的长度与参数声明无关。
一种常用的机制:
void foo(int arr[], int size);
另一种机制:声明为数组的引用
void foo(int &arr[10]);
这样函数会知道数组的长度,每次调用都会检查数组实参的长度和函数定义中指定的长度是否匹配
但是,这样缺乏灵活性
注意排列的顺序
习惯上,缺省实参在公共的头文件包含的函数声明中指定,而不是在函数定义中。
如果在函数定义中指定,那么缺省实参只会用在包含函数定义的那个文件中调用
典型情况:
可以在另外一个文件中重新声明函数,给b和para1也提供缺省参数
注意理解其中错误写法,也即不能给已提供缺省值的参数再次指定缺省值,哪怕值不变
例如有这个函数:
定义:
上面2种初始化都是可以的,但是个人更倾向第2种
于是通过函数指针调用函数也有两种用法:
pf(s1, s2);
(*pf)(s1, s2);
函数指针的数组:
int(*pf[10])(....)
函数指针可以作为函数的参数,也可以作为函数的返回值
作为函数参数:
这个复杂定义还好理解
作为函数返回值:
细细拆来:整体上是声明了一个函数ff,它有一个int类型的参数,它返回类型为函数指针类型,为int (*)(int *, int)
哇,巨复杂,不得不赞C++的编译器厉害。
为了更清晰的表达,最好使用typedef
指向extern "C'函数的指针“
但是注意:指向C函数的指针不能用指向C++的函数的指针初始化或赋值
函数调用在编译期,会检查实参与实参是否匹配。
注意,其中可能的话,会发生隐式类型转换,编译器只是给出警告
参数传递:
缺省情况是按值传递,实参的值拷贝到参数的存储区。函数处理的是实参的拷贝
按地址传递:引用和指针参数
1. 函数需要改变实参
2. 向函数传递大型对象时的效率考虑
3. 需要函数返回额外的结果
当需要2时,却不希望1发生,一个解决是:将参数声明为const引用类型
另外,如果用指针参数,需要在解引用前判断指针是否为NULL
数组参数:
数组总是按指针传递
数组的长度与参数声明无关。
一种常用的机制:
void foo(int arr[], int size);
另一种机制:声明为数组的引用
void foo(int &arr[10]);
这样函数会知道数组的长度,每次调用都会检查数组实参的长度和函数定义中指定的长度是否匹配
但是,这样缺乏灵活性
缺省实参:
注意排列的顺序
习惯上,缺省实参在公共的头文件包含的函数声明中指定,而不是在函数定义中。
如果在函数定义中指定,那么缺省实参只会用在包含函数定义的那个文件中调用
典型情况:
//ff.h
int ff(int a, int b, int c = 0);
int foo(double para1, float para2 = 3.1415);
int ff(int a, int b, int c = 0);
int foo(double para1, float para2 = 3.1415);
//ff.cpp
#include "ff.h"
int ff(int a, int b, int c)
{
//defination
//do something
}
int foo(double para1, float para2)
{
//also defination
//do other things
}
#include "ff.h"
int ff(int a, int b, int c)
{
//defination
//do something
}
int foo(double para1, float para2)
{
//also defination
//do other things
}
可以在另外一个文件中重新声明函数,给b和para1也提供缺省参数
//other .h or .cpp files
#include "ff.h"
int ff(int a, int b = 0, int c);
//错误写法:
//int ff(int a, int b = 0, int c = 0);
int foo(double para1 = 1.0, float para2);
//错误写法:
//int foo(double para1 = 1.0, float para2 = 3.1415);
#include "ff.h"
int ff(int a, int b = 0, int c);
//错误写法:
//int ff(int a, int b = 0, int c = 0);
int foo(double para1 = 1.0, float para2);
//错误写法:
//int foo(double para1 = 1.0, float para2 = 3.1415);
注意理解其中错误写法,也即不能给已提供缺省值的参数再次指定缺省值,哪怕值不变
指向函数的指针:
例如有这个函数:
#include <string>
int lexicoCompare(const string &s1, const string &s2)
{
return s1.compare(s2);
}
int lexicoCompare(const string &s1, const string &s2)
{
return s1.compare(s2);
}
定义:
int (*pf)(const string &s1, const string &s2);
pf = lexicoCompare;
pf = &lexicoCompare;
pf = lexicoCompare;
pf = &lexicoCompare;
上面2种初始化都是可以的,但是个人更倾向第2种
于是通过函数指针调用函数也有两种用法:
pf(s1, s2);
(*pf)(s1, s2);
函数指针的数组:
int(*pf[10])(....)
函数指针可以作为函数的参数,也可以作为函数的返回值
作为函数参数:
void sort(string *, string *, int (*)(const string &, const string &));
这个复杂定义还好理解
作为函数返回值:
int (*ff(int))(int *, int);
细细拆来:整体上是声明了一个函数ff,它有一个int类型的参数,它返回类型为函数指针类型,为int (*)(int *, int)
哇,巨复杂,不得不赞C++的编译器厉害。
为了更清晰的表达,最好使用typedef
void sort(string *, string *, int (*)(const string &, const string &));
typedef int(* PF_Type)(const string &, const string &);
void sort(string *, string *, PF_Type);
typedef int(* PF_Type)(const string &, const string &);
void sort(string *, string *, PF_Type);
int (*ff(int))(int *, int);
typedef int(* PF_Type)(int *, int);
PF_Type ff(int);
typedef int(* PF_Type)(int *, int);
PF_Type ff(int);
指向extern "C'函数的指针“
extern "C" void (*pf)(int);
但是注意:指向C函数的指针不能用指向C++的函数的指针初始化或赋值