C++学习_函数重载和默认参数

C++ 学习_函数重载和默认参数

我为什么要写C++系列博文呢?理由很蛋疼,因为C++的语法太庞杂了,从目前来看,后面我很难有精力和能力来总结一篇令我满意的”C++语法汇总”,所以干脆放弃那样做,将我学习的过程记录下来,这样写出来的东西包含的知识也比较全面。不过,由于我是学习的过程,所以在文章中难免有一些错误或者疏漏之处,希望大家不嫌麻烦的可以指出我的错误,本人会在第一时间修正该系列内容!
最后注:本系列博文会持续更新,并不断修正部分内容,希望关注的朋友可以一直看完,相信一定会有所收获,或者有所思考。。。

一、函数的默认参数

下面是封装的一个申请内存的函数,默认每次申请100字节的内存:

void* GetMemory(int bytesize = 100)
{
    return malloc(bytesize);
}

函数默认参数的作用:
- 如果这个函数需要多次使用相同的参数,采用默认参数会很方便(主要)
- 避免因为多次书写而手误写错(次要)
- 有些时候,对于调用的函数 ,刚开始可能不清楚或者不关心传递什么值 ,就给一个默认值先让代码跑起来 ,后续发现不合适了,再来重新设置

注意:
1. 缺省参数是作为实参传递给函数的,而不是在函数内部直接使用的
2. 若函数所有形参均有缺省值,则称为全缺省。传参时可以传(<=形参数目)个参数。从表面上看起来,像是从左往右依次赋值。

注:c/c++在默认情况下,函数的调用约定都是_cdecl,而这种调用约定规定:函数的参数是从右往左依次来传递的 所以在接收用户参数时,也是从右往左来传递的。
结合下面这个例子理解第二条:
假设现在有一个半缺省参数的函数,Fun(int a, int b = 10, int c = 20) 在调用时候 Fun(30) 这个30最后会传递给a。为什么传递给a ?是因为编译器在编译时会进行检测 Fun实际上有三个参数 ,而调用时只传递了一个 ,那编译器就会对函数的参数进行检查,看是否有缺省参数, 如果有后两个参数就使用缺省值了,我们传递的30就只能给a了,如果没有缺省参数,就会报错

  1. 若不是全缺省,则在设计函数形参的缺省值时,只能从右往左依次设定。
    原因:若缺省参数右边还有未设置缺省值的参数,出现下面这种情况就会有歧义:

    void Func(int a=1,int b);
    void main( void )
    {
    Func();//错误,因为b未赋实参
    Func(1);//错误,因为1赋给了a(左->右),b未赋实参
    }

    1. 缺省值只能放在函数声明/定义其中一个位置来设置,不能在这两个地方同时设置。

    注:建议将其放到声明的位置来设置(头文件中)。原因:当你写了一个库,编译后生成静态库(静态库中都是二进制文件,一般不可读),当别人想要用你的库,但是你又不想泄露源代码,就可以将头文件和静态库给他,头文件作为静态库的说明,而头文件中如果不包含函数缺省值的说明,对方就无法正确的使用你定义的函数缺省参数,所以建议将缺省值放到函数声明处设置,一般函数声明都放在头文件。
    不能同时设置的原因:若因为意外使得声明和定义处的函数缺省值不同,就会出现歧义(编译器就不知道使用哪个缺省值)

  2. 缺省值只能是常量或者全局变量

二、函数重载

1. 要求(除此之外均不构成函数重载):
1. 重载函数必须在同一作用域内
2. 重载函数名必须相同
3. 形参列表必须不同(个数 / 类型 / 参数类型顺序)

2. 函数重载实例:

//重载加法函数(整形和浮点型)
int add(int num1,int num2)//函数1
{
    return num1+num2;
}
double add(double num1,double num2)//函数2
{
    return num1+num2;
}
void main( void )
{
    int num1=1,num2=2,num3;
    double num4=2.3,num5=1.2,num6;
    num3=add(num1,num2);//调用函数1
    num6=add(num4,num5);//调用函数2
}

3. 为什么C语言不支持重载?
C++和C语言的编译方式不同。 C语言中的函数在编译时名字不变,或者只是简单的加一个下划线_(不同的编译器有不同的实现),例如,func() 编译后为 func() 或 _func()。

而C++中的函数在编译时会根据它所在的命名空间、它所属的类、以及它的参数列表(也叫参数签名)等信息进行重新命名,形成一个新的函数名。这个新的函数名只有编译器知道,对用户是不可见的。对函数重命名的过程叫做名字编码(Name Mangling),是通过一种特殊的算法来实现的。

Name Mangling 的算法是可逆的,既可以通过现有函数名计算出新函数名,也可以通过新函数名逆向推演出原有函数名。Name Mangling 可以确保新函数名的唯一性,只要函数所在的命名空间、所属的类、包含的参数列表等有一个不同,最后产生的新函数名也不同。
下面是一个测试用例:

#include <iostream>
using namespace std;

void display();
void display(int);

namespace ns{
void display();
}

class Demo{
public:
   void display();
};

int main()
{
    display();
    display(1);
    ns::display();
    Demo obj;
    obj.display();
    return 0;
}

该例中声明了四个同名函数,包括两个具有重载关系的全局函数,一个位于命名空间 ns 下的函数,以及一个属于类 Demo 的函数。它们都是只声明而未定义的函数。
在VS下编译后就会看到下面的信息,不同的编译器有不同的 Name Mangling 算法,产生的函数名也不一样。:
这里写图片描述

4. Else:
C++的函数可以在C环境编译,但是无法运行,如果要运行,可以采用下面的方法:

在函数名前加 extern “C” ,即按C风格编译这些函数,下面是一个使用的实例:

int add(int a,int b);//不可以运行
extern "C" int add(int a,int b);//可以运行
还可以这样:
extern "C"{
    函数1;
    函数2
    ……
}

其他知识点:
1. 传值调用和传址调用
- 传值调用
- 缺点:不能通过修改参数来改变外部实参
- 优点:函数的副作用不会影响外部实参
- 传址调用
- 优点:节省空间,效率高,在函数内部操作可以作用于函数外部
- 缺点:不安全
2. 浮代中的小数默认为double,若需指定为float型,需要在其后加上f.
eg:

1.0//double型
1.0f//float型

遗留问题:
1. 面向对象和面向过程的区别
2. extern和static的详细资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值