C++之函数

函数是C++的编程模块,要使用函数,必须完成下面工作:

1.函数原型声明

2.函数定义

3.函数调用

下面是一个简单的例子实现一个加法函数

int add(int a,int b); //函数原型声明
int main(){
    int sum = add(1,2);//函数调用
    return 0;
}
//函数定义
int add(int a,int b){
    return a+b;
}
1.函数与数组

 (1)C++中函数不能够返回数组,也就是不能够像下面这样声名函数的原型      

int[] get_arr(); //编译通不过的
如果你想通过指针返回数组,像下面这样
int* get_arr(){
    int arr[]={1,2,3}
    return arr;
}

   你会得到意想不到的数值,因为函数里面定义的变量是局部变量,在函数结束时就被系统自动释放了。

  (2)我们来看对一个整型数组求和,求和函数原型声名如下 

int sum_arr(int arr[],int n);//arr代表数组,n代表数组长度

   C++将数组名视为指针,将数组名解释为数组第一个元素的地址,即arr=&arr[0];

int cookies[]={1,2,3,4};
int total = sum_arr(cookies,4);

   传递的实参是cookies,其中cookies是数组名,根据C++规则,cookies是其第一个元素的地址,因此函数传递的是地址,而不是 整个数组的副本。

void swap(int x,int y);//交换x,y值的函数
int a =3,b=4;
swap(a,b);//函数调用后a,b的值不会交换

    函数参数使用普通参数时,C++是按值传递数据,也就是使用数据的副本。上面代码会有两个变量x,a的值是3,其中x是变量a的副本,同理y是变量b的副本。

2.函数和引用

 (1)编写使用基本类型作为参数的函数,最好不用采用按引用传递,最好采用按值传递。当数据比较大时(如结果或者类),引用参数将很有用。 

double cube(double a);//最好使用这种方式
double cube(double& a);//不推荐

  (2)引用  

int rat = 10;
int& rodent;
rodent = rat; //No,you can't do this.

    必须在声名引用变量的时候进行初始化,引用更接近const指针,必须在创建的时候进行初始化,一旦与某个变量关联起来,就将一直效忠他。

int& rodent = rat;

    实际上是下面代码的伪装表示

int* const ptr = &rat; 

   (3)临时变量、引用参数和const  

    如果实参与引用参数不匹配,C++将生成临时变量。当前,仅当参数为const引用时,C++才允许这样做,但以前不是这样。
如果引用参数是const,则编译器将在下面两种情况下生成临时变量:
    I:实参的类型正确,但不是左值
    II:实参的类型不正确,但是可以转化为正确的类型

   左值是什么呢?左值参数时可以被引用的数据对象,例如变量、数组元素、结果成员、引用和解除引用的指针都是左值。非左值包括字面常量(用引号括起的字符串除外,它们是由地址表示的)和包含多项的表达式。   

double refcube(const double& ra){
    return ra * ra * ra;
}
double side = 3.0;
double long edge = 5L;
double c1 = refcube(side); // ra is side
double c5 = refcube(edge); // ra is temporary variable
double c6 = refcube(7.0);  // ra is temporary variable
double c7 = refcube(side+10.0); // ra is temporary variable

   参数side都是有名称的double类型数据对象,因此可以为其创建引用,而不需要临时变量。然而,edge虽然是变量,类型却不正确,double引用不能够指向long,另一方面,参数7.0和side+10.0的类型正确,但是没有名称,在这些情况下,都会生成一个临时变量,并让ra指向它。这些临时变量只在函数调用期间存在,此后编译器可以随意将其删除。

   那为什么对于常量引用,这种行为是可行的,其它情况下却不行呢?

void swap(int& a,int& b){
    int temp;
    temp = a;
    a = b;
    b = temp;
}

   如果在早期C++较宽松的规则下,执行下面操作将会发生什么情况呢?

long a=3,b=5;
swap(a,b);

   这里的类型不匹配,因此编译器将创建两个临时int变量,将他们初始化为3和5,然后交换临时变量的内容,而a和b保持不变。

   简而言之,如果接受引用参数的函数的意图是修改作为参数传递的变量,则创建临时变量阻止这种意图的实现。解决方法是禁止创建临时变量,现在的C++标准正是这样做的。(然而,在默认情况下,有些编译器仍将发出警告,而不是错误消息,如果看到有关临时变量的警告,请不要忽略)

3.函数模版

    (1)函数模板的声明与定义.比如实现一个交换两个变量值的函数

//声明函数模版
template <typename T>
void swap(T& a,T& b);
//定义函数模版
template <typename T>
void swap(T& a,T& b){
    T temp ;
	temp = a;
	a = b;
	b = temp;
}

    注意:函数模版的声明跟定义需要放到一个文件中,一般是放到头文件.

  (2)显示具体化
    I:对于给定的函数名,可以有非模版函数、模版函数和显示具体化模版函数以及它们的重载版本。
    II.显示具体化的原型和定义应以template<>打头,并通过名称来指出类型。

    III.具体化优于常规模版,而非模版函数优于具体化和常规模版

   下面是用户交换job结构的非模版函数、模版函数和具体化的原型。

struct job{
    char name[40];
	double salary;
	int floor;
};
//no template function prototype
void swap(job& a,job& b);
//template prototype
template <typename T>
void swap(T& a,T& b);
//explicit specialization for the job type
template<>
void swap<job>(job& a,job& b);

    如果有多个原型,则编译器在选择原型时,非模版版本优先于显示具体化和模版版本,而显示具体化优先于使用模版生成的版本。  

int main(){
    double u,v;
    ...
    swap(u,v); //use template
    job a,b;
    ...
    swap(a,b); // use void swap<job>(job& a,job& b);  	
    return 0;
}

    注意:swap<job>中的<job>是可选的,因为韩素的参数类型表明,这是job的一个具体化,因此,该原型也可以这样编写:    

template<>
void swap(job& a,job& b); //simpler form
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值