`
geke260
  • 浏览: 13504 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

C++函数学习

阅读更多
1. 函数不能返回另一个函数或者内置数组类型,但可以返回指向函数的指针,或者指向数组元素的指针的指针。
2. 早期的C/C++在声明时可以不指定返回类型,如果缺少显示返回类型,函数的返回值将被假定为int型。现在标准的C++必须指定返回类型,否则编译出错。
3. 早期的C在声明时可以不指定形参列表,因为C不支持重载,编译不会出现问题,但是在C++中,由于支持重载,必须制定形参列表。(在vs 2008中测试过)
4. 在参数传值时,如果参数是指针(引用),则形参的初始化根据指针的初始化规则。指针的初始化规则 4.2.5节。可以将指向const对象的指针初始化为指向非const对象的指针,但是不能将指向非const对象的指针初始化为指向const对象的指针。这条规则不适应于一般的非引用(或者非指针)对象的传值,因为调用的时候形参复制了实参的值,所以可以用const对象的实参初始化非const对象的形参,同样的,可以用非const对象初始化const对象的形参)
5. 当函数的形参非指针或者引用类型时,且形参声明为const时,但是编译器会忽略掉这个const,如下两个函数定义:
void fcn ( const int i ){ /* 函数体*/}
void fcn ( int i ){ /*函数体*/}
这是编译时会出现重定义错误。这种用法是为了支持对C语言的兼容,因为在C语言中,具有const形参或非const形参的函数并无区别。也可以说是函数调用时会将值复制给fcn,这时并不需要考虑形参是否为const。但是当函数形参为指针类型时
void fcn ( const int * i ){ /* 函数体*/}
void fcn ( int  *i ){ /*函数体*/}
则这两个函数是不同的重载函数,这种情况同样适用于引用类型的形参。
6.在函数需要返回多个值的时候,引用传值或者指针传值是个不错的选择。
7.如果函数具有普通的非const引用形参,则显然不能用const对象进行调用。而且当传递过来为右值或者具有需要转换类型的对象时,同样不能进行调用。当传入值为需要转换类型的对象时,这时会产生一个临时对象,函数内所作的修改只反映到对临时对象,违背了调用者的本意(对实参进行修改),所以编译器会提示出错。而当传入值为右值时,右值不能初始化引用类型或者出现临时对象错误。
8.在实参为数组类型时,由于形参只能是其对应的作为实参的数组元素的指针类型或者是数组的引用。当形参为指针引用类型时,因为调用时总会产生临时对象,有可能出现7中的问题。当形参声明为数组的应用时,编译器不会讲数组实参转化为指针,而是传递数组的引用本生。在这种情况下,数组大小成为形参和实参类型的一部分。编译器会检查数组实参的大小与形参的大小是否匹配。
例一  :形参为指针引用类型时
#include<cstdio>
void func1( int *const&a);
void func2( int *&a);
int main(){
int myarray[5] = {1,2,3,4,5};
func1(myarray);
func2(myarray); //形参为非const指针引用,由于会产生临时对象,编译会报错
    }   
int func1(int *&a){
/*函数体*/
}
void func2(int *const&a){
/*函数体*/
}
例二 :形参为数组引用类型时
#include<cstdio>
void  func1(int (&a)[4]);
void func2(int (&a)[5]);
int main(){
int myarray[5] = {1,2,3,4,5};
func1(myarray); //编译不通过,形参和实参的数组长度不一致
func2(myarray); //输出20,得到数组的实际长度。
printf("%d",myarray[3]);
getchar();
    }  
void func1(int (&a)[4]){
/*函数体*/
}
void func2(int (&a)[5]){
   printf("%d\n",sizeof(a));
}
9.默认实参可以是任意的表达式,如果在函数调用时,需要用到默认实参,则在调用时求解改表达式。既可以在函数声明时也可以在函数定义中指定默认实参。但是,在一个文件中,只能为一个形参指定默认实参一次。通常应在函数声明中指定默认实参,并将改声明发那个在合适的头文件中。如果在函数定义的形参表中提供默认形参,那么只有在包含改函数定义的源文件中调用该函数时,默认实参才是有效的。
//ff.h
int ff(int  i=0);

//ff.cc
#include "ff.h"
int ff(int  i=0) {/* 函数体*/} //出错,因为包含了头文件,为形参i指定了两次默认实参。

10.编译器隐式地将在类内定义的成员函数当做内联函数。如果成员函数写在类外,需要在声明时加inline才是内联的。必须将成员函数定义在类声明的头文件中。当成员函数声明为inline时,函数定义不必在加inline。
11.如果成员函数被声明为const成员函数,那么函数定义是形参列表之后也必须有const。
12.在合成的默认构造函数中,对内置数据类型的成员变量的初始化如将依据变量的初始化规则初始化类中的所有成员。对类类型的成员采用该类自身的默认构造函数初始化。内置类型成员的初值依赖于对象如何定义。如果对象在全局作用域中定义或定义为静态局部对象,这这些成员初始化为0,。如果对象在局部作用域中定义,这些成员没有初始化(即初值不确定)。
13. 如果局部地声明一个函数,则该函数声明会屏蔽掉在外层作用域中声明的同名函数。由此类推,每一个版本的重载函数都应该在同一个作用域中声明。一般来说,局部地声明函数是一种不明智的选择。函数的声明应该放在头文件中。
例子:
void print(const string &);
void print(double);
void fun(){
void print(int);
  print("value");//编译错误,因为外部的声明被屏蔽了。
}
14.函数的匹配过程。
在函数匹配过程中,通过类型提升实现的转换优于其他标准转化。在标准转化时,从char到unsigned char的转换的优先级不比从char型到double型的转换高。枚举值会被提升为int型或者更大的类型,具体的提升类型型取决于枚举成员的值。 
15.可以使用函数名对函数指针做初始化或者赋值。直接引用函数名等效于在函数名上应用取地址符号。
cmpFcn pf1 = lengthCompare;
cmpFcn pf2 = &lengthCompare;
cmpFcn为函数指针,两者等效。
指向函数的指针可用于调用它所指向的函数。可以不需要使用介引用符号,直接通过指针调用函数。
pf2(“hi”,”world”);
不会出现编译错误。
函数的形参可以为指向函数的指针,这种形参可以用以下两种形式编写:
void useBigger(const string &, const string &,bool(const string &, const string & ));
void useBigger(const string &, const string &,bool(*)(const string &, const string & ));
函数的返回类型可以是函数指针类型,但是不能为函数类型。
示例:
#include<cstdio>
typedef int func(int ,int);
typedef int (*funcp)(int ,int);
int compare(int ,int);
int main(){
   func f1 = compare; //出错,不能用函数名为函数类型的变量赋值,只能为函数指针类型的变量赋值
   func *f2 = compare;  //正确。f2为函数指针
   funcp fp = compare;  //正确。fp为函数指针
}
int compare(int n,int m){
return n>m;
}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics