参数类型检查
C++是一种静态强类型的语言,对于每一次的调用,编译时都会检查其实参,调用函数时,对于每一个实参,其类型都必须与对应的形参类型相同,或具有可被转化为该形参类型的类型。
参数传递
利用const 引用来避免复制,如果使用引用形参的唯一目的是避免复制实参,则应将形参定义为const引用。
非const引用形参只能与完全同类型的非const对象关联
应该将不需要修改的引用形参定义为const引用,普通的非const 引用形参在使用时不太灵活,这样的形参既不能用非const对象初始化,也不能用字面值或产生右值的表达式初始化。
string::size_type find_char(string &s, char c)
{
string::size_type i=0;
while(i!=s.size() && s[i]!=c)
{
i++;
}
return i;
};
int main()
{
cout<<find_char("hello",'o')<<endl; //用字符串hello当做实参,传递给非const 引用,调用失败,如果将形参改为const 引用,调用成功
getchar();
return 0;
}
合成的默认构造函数
合成的默认构造函数一般适用于仅包含类类型成员的类,而对于内置类型和复合类型成员的类,则通常应该定义他们自己的默认构造函数初始化这些成员。
内置类型成员的初值依赖于对象如何定义,如果对象在全局作用域中定义(不在任何函数内)或定义为静态局部对象,则这些成员应该初始化为0,如果对象在局部作用域中定义,则这些成员没有初始化。
数组形参
通常将数组形参直接定义为指针要比使用数组语法好,这样明确函数要操纵的是指向数组元素的指针,而不是数组本身,当编译器检查数组形参关联的实参时,只会检查实参是不是指针,指针的类型是否匹配,而不会检查长度。
通常情况下,数组形参以普通的非引用类型传递,此时数组会转换为指针,一般来说非引用类型的形参会初始化为其相应类型的实参副本,形参复制的是数组元素指针的值而不是数组本身。
通过引用来传递数组
如果形参是数组的引用,编译器不会讲数组实参转换为指针,而是传递数组的引用本身,此时,编译器会检查数组实参的大小和形参的大小是否匹配。
此外,引用数组的定义是int (&arr)[10] ,其中的括号不能省
void printValues1(int (&arr)[10])
{
for(int i=0;i<10;i++)
{
cout<<arr[i]<<endl;
}
}
void printvalues2(int *p,int len)
{
while(len--)
{
cout<<*p<<endl;
p++;
}
}
int main()
{
int k[10]={1,2,3,4,5,6,7,8,9,10};
int a[5]={1,2,3,4,5};
printValues1(k);
printvalues2(a,5);
getchar();
return 0;
}
返回非引用类型
函数的返回值用于初始化在调用函数处创建的临时对象,在求解表达式时,如果需要一个地方存储其运算结果,编译器会创建这个临时对象,如果返回类型不是引用,在调用函数的地方会将函数的返回值复制给临时对象,返回值可以使函数的局部对象,也可以是求解表达式的结果。
int func(const int a)
{
int b=a;
return b;
}
int main()
{
int t=func(10);
cout<<t<<endl;
getchar();
return 0;
}
返回引用
当函数返回引用类型时,没有复制返回值,相反返回的是对象本身。
const string &shortestString(const string &s1,const string & s2)
{
return s1.size()<s2.size()?s1:s2;
}
int main()
{
string s1("hello"),s2("what");
shortestString(s1,s2);
getchar();
return 0;
}
千万不要返回局部对象的引用和局部对象指针
当函数执行完毕时,将释放分配给局部对象的存储空间,任何对局部对象的引用都会指向不确定的内存。
const string &shortestString(const string & s1)
{
string temp=s1;
return temp;
}
int main()
{
string s1("hello"),s2("what");
s2=shortestString(s1);
getchar();
return 0;
}
运行报错
重载函数
void print(int i)
{
cout<<"int_i"<<endl;
cout<<i<<endl;
}
void print()
{
cout<<"hello"<<endl;
}
int main()
{
print(5);
print();
getchar();
return 0;
}
两个重载函数print(int i) 和print
在任何程序中仅有一个main示例,main函数不能重载
如果局部地声明一个函数,则该函数将屏蔽而不是重载在外层作用域声明的同名函数,重载函数应该在同一个作用域中声明。
void print(int i)
{
cout<<"int_i"<<endl;
cout<<i<<endl;
}
void print()
{
cout<<"hello"<<endl;
}
int main()
{
void print(string str);
print(5);
getchar();
return 0;
}
重载和const形参
仅当形参是引用或指针时,形参是否为const才有影响
可基于函数的引用形参是指向const对象还是指向非const对象,实现函数的重载,将引用形参定义为const来重载函数,如果形参不是引用,那么不能利用是否为const来实现重载。
Record lookup(Account &);
Record lookup(const Account &);
const Account a(0);
Account b;
Lookup(a); //调用 Record lookup(const Account &);
Lookup(b); //调用 Record lookup(Account &);
指向函数的指针
函数指针是指指向函数而非指向对象的指针。
bool (*cmpFcn)(const string &,const string&); 将cmpFcn声明为指向函数的指针,用typedef简化函数指针的定义
typedef bool (*cmpFcn)(const string &,const string&)。 cmpFcn定义为指向返回bool类型并带有两个const string 引用形参的函数的指针,
指向函数的指针的初始化和赋值
在引用函数名但有没有调用该函数时,函数名将自动解释为指向函数的指针,如下所示:
bool lengthCompare(const string &,const string&); lengthCompare被解析为该类型的函数指针。
返回指向函数的指针
函数可以返回指向函数的指针,如下所示:
Int (*ff(int))(int*,int);
ff是函数,带有形参为int型,该函数的返回类型是函数指针,指向int型,参数是(int *,int)。