C++——函数


函数重载

在相同的作用域,定义同名的函数,但是它们的参数有所区分,这样的函数之间的关系称为函数重载。

函数重载匹配

调用重载关系的函数时,编译器将根据实参和形参匹配程度,自动选择最优的重载版本。
当前g++编译器匹配的一般规则:
完全匹配 >=常量转换 > 升级转换 > 降级转换 > 省略号

函数重载的原理

C++编译器是通过对函数进行换命,将参数表的类型信息整合到新的名字中,解决函数重载和名字冲突的矛盾。
使用关键字“extern”用于声明C++中的函数,要求该函数不做换名以方便C程序调用该函数。

代码示例

  • overload.cpp
#include <iostream>
using namespace std;
int foo(int i){
    cout << "foo(int)" << endl;
}
void foo(int i,int j){
    cout << "foo(int,int)" << endl;
}
void foo(int a,float f){
    cout << "foo(int,float)" << endl;
}
int main(void)
{
    foo(10);
    foo(10,20);
    foo(10,1.23f);
   
    /*函数指针的类型决定其匹配的版本*/
    void (*pfoo)(int,float) = foo;
    pfoo(10,20);

    return 0;
}

  • 执行结果
    在这里插入图片描述
  • 02overload.cpp
#include <iostream>
using namespace std;
//char->int:升级转换
void bar(int i){
    cout << "bar(1)" << endl;
}
//char->const char:*常量转换*
void bar(const char c){
    cout << "bar(2)" << endl;
}
//short->char:降级转换
void func(char c){
    cout << "func(1)" << endl;
}
//short->int:升级转换
void func(int i){
    cout << "func(2)" << endl;
}
//省略号匹配(最差)
void hum(int i,...){
    cout << "hum(1)" << endl;
}
//double->int:降级转换
void hum(int i,int j){
    cout << "hum(2)" << endl;
}
int main(void)
{
    char c = 'a';
    bar(c);
    short s = 10;
    func(s);
    hum(10,1.23);
    return 0;
}
  • 执行结果
    在这里插入图片描述

函数的缺省参数(默认实参)

  1. 可以为函数的部分或者全部参数指定缺省值,调用该函数时,如果不给传实参,可以用缺省值作为相应的实参值。
  void func(int a,int b,int flag=0){}
  1. 靠右原则,如果函数的一个参数有缺省值,那么这个参数右侧的所有参数都必须带有缺省值。
	void func(int a = 0,int b){}//error
	void func(int b,int a = 0){}//ok
  1. 如果函数的定义和声明分开,缺省参数应该写在函数的声明部分,而定义部分不写。
	void func(int a = 缺省值);//函数声明
	void func(int a){...};//函数定义

代码示例

  • defarg.cpp
#include <iostream>
using namespace std;
//函数声明
void foo(int a,int b = 200,int c = 300);
int main(void)
{
    foo(10);//10,200,300
    foo(10,20);//10,20,300
    foo(10,20,30);//10,20,30
    return 0;
}
//函数定义
void foo(int a,int b/*=200*/,int c/*=300*/){
    cout << a << ',' << b << ',' << c
        << endl;
}
  • 执行结果
    在这里插入图片描述

哑元函数

  1. 只有类型而没有变量名的形参成为哑元
	void func(int/*哑元*/){...}
  1. 使用哑元的场景
    • 操作符重载中,区分前后++/- -
    • 为了兼容旧代码

代码示例

  • 02defarg.cpp
#include <iostream>
using namespace std;
//函数声明
void foo(int a,int=0/*哑元*/);
int main(void)
{
    foo(10);//10,200,300
    foo(10,20);//10,20,300
    foo(10,20,30);//10,20,30
    return 0;
}
//函数定义
void foo(int a,int=0){
    cout <<  "a = " << a << endl;
}
  • 执行结果
    在这里插入图片描述

内联函数(inline)

  1. 使用inline关键字修饰的函数,表示这个函数是内联函数,编译器将常识做内联优化,避免函数的调用开销,提高程序的执行效率。
  2. 说明:
    • 多次调用的小而简单的函数适合内联。
    • 调用次数极少或大而复杂的函数不适合内联。
    • 递归函数不能内联优化。
  • 注:内联只是一种建议而不是强制要求,一个函数能否内联优化主要取决于编译器,有些函数不加inline修饰,编译器也会默认处理为内联优化;有些函数即便加了inline的修饰也会被编译器忽略。

C++的动态内存分配

之前C语言中动态内存分配使用:

  • 分配(malloc())
  • 释放(free())
  • 错误处理(根据返回值进行错误处理)

而现在C++中使用操作符实现动态内存管理

  • 分配:new、new[]
  • 释放:delete、delete[]
  • 错误处理:C++异常机制

代码示例

  • new.cpp
#include <iostream>
using namespace std;

int main(void)
{
    int* pi = new int;
    *pi = 123;
    cout << *pi << endl;
    delete pi;//防止内存泄露
    pi = NULL;//避免野指针
    
    //new内存同时初始化
    int* p2 = new int(321);
    cout << *p2 << endl;//321
    delete p2;
    p2 = NULL;

    //new数组,包含10元素
    int* pa = new int[10];
    for(int i=0;i<10;i++){
        pa[i] = i;
        cout << pa[i] << ' ';
    }
    cout << endl;
    delete[] pa;
    pa = NULL;

    //new数组,同时初始化,需要C++11标准支持
    int* pa2 = 
        new int[10]{9,8,7,6,5,4,3,2,1,0};
    for(int i=0;i<10;i++){
        cout << pa2[i] << ' ';
    }
    cout << endl;
    delete[] pa2;
    pa2 = NULL;

    return 0;
}
  • 执行结果
    在这里插入图片描述

引用(reference)

定义

  1. 引用就是某个变量的别名,对引用的操作与对该变量本身完全相同。
  2. 语法
	类型 & 引用名 = 变量名;
 	注:引用在定义时必须要初始化,初始化以后绑定的目标不能再修改。
 	注:引用的类型和它绑定的目标变量类型要一致
 	eg:
 	int a = 10;
 	int& b = a;//b就是a的别名
 	b++;
 	cout << a << endl;//11
 	int c = 20;
 	b = c;//赋值操作,不是改变引用的目标
 	cout << a << endl;//20

常引用

  1. 定义引用是加 const 修饰,即为常引用,不能通过常引用修改引用的目标。
	int a = 10;
	const int& b = a;//b就是a的常引用
	//int const& b = a;//和上面等价	
  1. 普通的引用也可以称为左值引用,只能引用左值;而常引用也可以称为万能引用,既可以引用左值又可以引用右值。
  2. 关于左值和右值
左值(lvalue):可以放在赋值操作符左侧,可以被修改
-->非const普通变量都是左值
右值(rvalue):只能放在赋值操作符右侧,不能被修改
-->常量
-->临时变量

	int a = 100;
	//a(int)-->tmp(double)
	double& r = a;//error 
	int& r = 100;//error

引用型函数参数

  1. 将引用用于函数参数,这时形参就是实参的别名,可以通过形参直接修改实参变量的值,同时还能避免参数值的传递过程,提高代码执行效率。
  2. 引用参数可能意外修改实参的值,如果不希望修改实参变量本身,可以将形参定义为常引用,提高传参效率的同时还可以接受常量型实参。

代码示例

  • reference.cpp
#include <iostream>
using namespace std;
int main(void)
{
    int a = 66;
    int& b = a;//b引用a,b就是a的别名
    cout << "&a=" << &a << endl;
    cout << "&b=" << &b << endl;
    b++;
    cout << "a=" << a << endl;//67
    cout << "b=" << b << endl;//67

    //int& r;//error
    //double& r = a;//error

}
  • 执行结果
    在这里插入图片描述
  • constref.cpp
#include <iostream>
using namespace std;
int func(void){
    int num = 123;
    //编译会生成临时变量保存return数据
    return num;//int tmp=num
}
int main(void)
{
    //函数返回的是临时变量(右值),普通引用
    //无法接收,常引用可以
    //int res = tmp;
    //int& res = func();//error
    const int& res = func();//ok
    cout << res << endl;//123

    //100是常数(右值),普通引用不能引用右值
    //int& ri = 100;//error
    //常引用可以引用右值
    const int& ri = 100;//ok

    int i = 200;
    //i是左值,但是给double类型rd初始化时需要
    //先做隐式转换,转换之后结果会保存到一个
    //临时变量中,临时变量都是右值,所以error
    //double& rd = i;//error

    //rd实际引用的是临时变量,不是i本身
    const double& rd = i;
    cout << "&i=" << &i << endl;
    cout << "&rd=" << &rd << endl;

    return 0;
}
  • 执行结果
    在这里插入图片描述
  • refArg.cpp
#include <iostream>
using namespace std;

/*void swap1(int* x,int* y){
    *x = *x ^ *y;//011 ^ 101 = 110(x)
    *y = *x ^ *y;//110 ^ 101 = 011(y)->3
    *x = *x ^ *y;//110 ^ 011 = 101(x)->5
}*/
void swap2(int& x,int& y){
    x = x ^ y;
    y = x ^ y;
    x = x ^ y;
}
int main(void)
{
    int a = 3,b = 5;
    //swap1(&a,&b);
    swap2(a,b);
    //a=5,b=3
    cout << "a=" << a << ",b=" << b << endl;
    return 0;
}
  • 执行结果
    在这里插入图片描述

  • 02refArg.cpp

#include <iostream>
using namespace std;
struct Student{
    char name[128];
    int age;
    int no;
};
void print(const Student& s){
    cout << "我叫" << s.name << ",今年" <<
        s.age/*++*/ <<"岁,学号是" << s.no 
        << endl;
}
int main(void)
{
    const Student stu = {"老王",45,10086};
    print(stu);
    print(stu);
    print(stu);
    return 0;
}
  • 执行结果
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值