函数是一个命名了的代码块,可有0个或多个参数。
函数声明应该放到头文件中。 这样做的好处在于:同一函数的所有声明一致;想改变函数的接口,只需要改变函数的声明的即可。
引用传递: 形参的类型决定了形参和实参的交互方式。 当形参是引用类型时,如其他引用一样,引用形参是对应实参的别名。
值传递: 将实参的值拷贝给形参,此时形参和实参是两个相互独立的对象。对形参的改变,不会影响到实参的值。
*指针形参
void reset(int *ip)
{
*ip=0;
ip=0;
}
int i=42;
reset(&i)
此时形参和实参是两个相互独立的对象。
实现两个数交换的两种方法(C++中,建议使用引用类型代替指针形参)
void swap1(int *a,int * b)//指针 参数是两个指针变量
{
int tmp;
tmp=*a; //把a指向的值赋给tmp
*a=*b; //把b指向的值赋给a指向的值
*b=tmp; //把tmp的值赋给b指向的值
//这样就达到了变换a,b指向的值的目的
}
void swap2(int &a,int &b)//引用 参数是两个整型变量的引用
{
//引用就是他本身的值,所以直接交换两个的值就行了。
int tmp;
tmp=a;
a=b;
b=tmp;
}
当拷贝大的类类型对象或容器对象时,比较低效。
一个return只能返回一个参数,通过引用带出多个参数。
void fcn(const int i){};
void fcn(int i){};
上面这两个函数是一样的,不能重载。因为当形参有顶层const时,传给它的是const或非const均可以。
顶层const:指针本身是一个常亮;
底层const:指针所指的对象是一个常量。
const int ci=42; //顶层const
非常量可以初始化一个底层const对象,反之则不行;
同时,一个普通类型的引用,只能用同类型的对象初始化。
顶层const作为形参时,实参传递是const或非const均可;
例如:
bool is_empty(string &s)
{
return s.empty();
}
这种情况下,限制了该函数所能接受的实参类型,无法把const、对
象、字面值常量或者需要类型转换的对象传递给普通的引用形参。
另一方面,也可能带来误导,可修改字符串s。
应该把形参改为 const string &s
数组的两个特性:不允许拷贝数组、数组名转换为指针
int main(int argc, char *argv[])
{
//其中argc是argv[][]的行数
}
initializer_lsit是一种标准库类型。适用于函数的实参未知,但类型都相同的情况下。
int icount(initializer_lsit il)
{
int count =0;
for(auto val :il)
{
count += val;
}
return count;
}
icount({1,2,3,4,5});
函数的返回类型是void时,如果函数末尾没有return时,也可以。因为在函数的最后一句会隐式的调用return。
return exp;
函数终止后,局部变量的引用将不再指向有效的内存区域。
char &get_val(string &str, int index)
{
return str[index];
}
void main
{
string s("a value");
get_val(s,0) = 'A'; //改为 A value
}
int (*func(int i))[10];
重载函数:名字相同,但是函数参数列表不同。
注:返回类型不算。
顶层const
(因为当形参有顶层const时,传给它的是const或非const均可以)。
(因为当形参有顶层const时,传给它的是const或非const均可以),所以下面两组函数是重复声明。
Record lookup(phone);
Record lookup(const phone);
Record lookup(phone*);
Record lookup(phone* const );
形参是指针或者引用。将是底层const,可通过指向的对象时常量对象还是非常量对象实现重载。
一方面,const不能转换为其他类型,只能将const转换为const;另一方面,相反的,非const可以转换为const,但是当同时存在非常量和const两个版本的形参时,编译器会优先选择非常量版本的函数,
Record lookup(Account &);
Record lookup(const Account &);
Record lookup(phone*);
Record lookup(phone* const );
规定:一旦某个形参被赋予了默认值,那么它后面的所有形参都必须被赋予默认值。
将函数指定为内联函数,通常就是在每个调用点进行展开。
constexpr函数---暂时用不到。
如:assert(expr),如果表达式为真,什么都不做;如果表达式为假,则输出信息并终止程序。
如果你把代码夹在#ifdef DEBUG 和对应的 #endif 中间,那么这段代码只有在调试(DEBUG)下才会被编译。也就是说,如果你在RELEASE模式下,这些代码根本就不会存在于你的最终代码里头。
#include
using namespace std;
#ifdef DEBUG
inline void msg()
{
cout<<"I'm testing";
}
#else
inline void msg() {}
#endif
int main()
{
msg();
return 0;
}
背景:有几个重载函数,当一个调用函数调用重载函数时,可能会发生二义性。
解决办法:寻求最佳匹配。
bool lengthCompare(const string &,const string &);
bool (*pf) (const string &,const string &)
pf = lengthCompare; // 指向名为lengthCompare的函数
pf = &lengthCompare; //等价,取址操作符是可选的。
//直接使用
bool b1 = pf("hello", "world");
bool b2 = (*pf) ("hello", "world"); //等价调用
//第三个形参是函数类型,自动转换为指向函数的指针
void useBigger(const string &, const string &, bool pf (const string &,const string &));
|
void useBigger(const string &, const string &, bool (*pf) (const string &,const string &)); //自动转换为函数指针
如上面,这样显得函数冗长。
通常:typedef bool Func(const string &, const string &) ;
void useBigger(const string &, const string &, Func));