c++的函数重载,命名空间

函数多态时c++在c语言的基础上新增的功能。默认参数让我们能够使用不同数目的参数调用同一个函数,而函数多态(函数重载)让我们能够使用多个同名的函数 。术语“多态”指的是有多种形式,因此函数多态允许函数可以有多个形式。类似地,术语“函数重载”指的是可以有多个同名的函数,因此对名称进行了重载。这两个术语指的是同一回事,但我们通常使用函数重载。可以通过函数重载来设计一系列函数----它们完成相同的工作,但是用不同的参数列表。

1、概念

用相同的函数名定义多个不同的功能称为函数重载。重载的函数根据参数的个数和类型进行区分,但不能单独根据返回类型进行区分。函数重载的关键是函数的参数列表(函数特征标)。如果两个函数的参数数目和类型相同,同时参数的排列顺序也相同,则它们的特征标相同,而变量名是无关重要的。c++允许定义名称相同的函数,条件是它们的特征标不同。如果参数数目或参数列表不同,则特征标也不同。

2、规则

函数重载的规则:

1、函数名称必须相同

2、参数列表(函数特征标)必须不同(个数不同,类型不同,参数排列顺序不同等)

3、函数的返回类型可以相同也可以不同

4、仅仅返回类型不同不足以称为函数重载的重载

5、需要在同一作用域下

//swap_reload.cpp
#include <iostream>
using namespace std;

void swap_val(int *a,int *b)
{
    *a = *a + *b;
    *b = *a - *b;
    *a = *a - *b;
    cout<< "swap_val(int*,int*)" << *a << " " << *b << endl;
}

// void swap_val(int *b,int *a) //error 不能够重载
// {
//     *a = *a + *b;
//     *b = *a - *b;
//     *a = *a - *b;
// cout<< "swap_val(int*,int*)" << *a << " " << *b << endl;
// }


void swap_val(float *a,float *b)
{
    *a = *a + *b;
    *b = *a - *b;
    *a = *a - *b;
    cout<< "swap_val(float*,float*)" << *a << " " << *b << endl;
}
void swap_val(char *a,char *b)
{
    *a = *a + *b;
    *b = *a - *b;
    *a = *a - *b;
    cout<< "swap_val(char*,char*)" << *a << " " << *b << endl;
}
void swap_val(bool *a,bool *b)
{
    *a = *a + *b;
    *b = *a - *b;
    *a = *a - *b;
    cout<< "swap_val(bool*,bool*)" << *a << " " << *b << endl;
}

int main()
{
    int a=3,b=4;
    swap_val(&a,&b); //根据 ab的数据类型来决定调用哪一个函数
    //cout<<a<<" "<<b<<endl;

    float a1=3.5,b1=4.5;
    swap_val(&a1,&b1); //根据 ab的数据类型来决定调用哪一个函数
    //cout<<a1<<" "<<b1<<endl;

    bool a2 = true,b2 = false;
    swap_val(&a2,&b2); //根据 ab的数据类型来决定调用哪一个函数
    //cout<<a2<<" "<<b2<<endl;  

    char a3='a',b3='b';
    swap_val(&a3,&b3); //根据 ab的数据类型来决定调用哪一个函数
    //cout<<a3<<" "<<b3<<endl;

    return 0;
}

3、作用

函数重载的作用主要是两点:

1、解决函数名字资源问题

2、函数调用的时候很方便,自动根据不同的函数调用不同函数(静态多态-编译时候多态)

4、问题

当默认参数和函数重载遇到会发生事情呢?

#include<iostream>

using namespace std;

//将void test()放在命名空间就不会产生歧义
// namespace spaceA
// {
//     void test()
//     {
//     }
// }

void test()
{
}

void test(int x=10)
{
}

int main()
{

    // test(11);//调用 的是:void test(int x=10)
    test();//调用的是???歧义

}

 当函数没有参数列表和函数全部参数都有默认参数的时候,当cpp文件中都存在上述两种函数声明或定义的时候,当我们调用上述两种函数之一的时候,编译器会给我们报错,因为两种函数都符合我们的需求,这里就存在函数二义性,编译器不知道我们需求的是哪一个函数,从而程序报错。

解决方法也很简单,把函数定义或声明放到命名空间内,然后通过命名空间来调用指定函数。

4、命名空间(名称空间)

c++新增了这样一种功能,即通过定义一种新的声明区域来创建命名的名称空间,这样做的目的之一是提供一个声明名称空间的区域。一个名称空间中的名称不会与另外一个名称空间的相同名称冲突,同时允许程序的其他部分使用该名称空间中声明的东西。

命名空间创建的格式

namespace 名称空间名字 
{
    //声明定义变量
    //声明定义函数
    //定义结构体/共用体/枚举 数据类型
    //声明类 定义对象 
    
    //可嵌套定义
    //namespace 名称空间名字   
}

名称空间可以是全局的,也可以位于另一个名称空间中,但不能位于代码块中。因此,在默认情况下,在名称空间中声明的名称的链接性为外部的(其他文件也可以使用)(除非它引用了常量)

​当然,当我们定义了一个名称空间之后,需要有一种方法来访问给定名称空间中的名称,最简单的方法就是通过作用域解析运算符(::),使用名称空间来限定该名称;

namespace Jack{...}

Jack::pail = 12.34 //use a variable

Jack::swap(); //use a function

Jack::Jim::a = 12 //create a namespace

未被装饰的名称(pail)称为未限定的名称,包含名称空间的名称(Jack::pail)称为限定的名称

5、名称空间的特性

1、using声明和using编译指令

using声明使特定的标识符可用,using编译指令使整个名称空间可用。

using声明由被限定的名称和它前面的关键字using组成,using声明将特定的名称添加到它所属的声明区域中。using声明式一个名称可用,而using编译指令使所有的名称都可用。using编译指令由名称空间名和它的前面的关键字using namespace组成,它使名称空间中所有名称都可用,而不需要使用作用域解析运算符,在全局声明区域中使用using编译指令,将使该名称空间的名称全局可用。这种情况已经出现过多次:

#include

using namespace std; //using编译指令,使该cpp文件可以访问std这个名称空间

有关using编译指令和using声明,需要记住一点是,它们增加了名称冲突的可能性。也就是说,如果由名称空间a和b,并在代码中使用作用域解析运算符,则不会存在二义性。

但事实上,编译器不允许我们同时使用不同名称空间同一变量名称的using声明,因为这将导致二义性。

如果函数被重载,则一个using声明将导入所有的版本

2、using编译指令与using声明比较

1、using声明可以单独使用名称空间中某个特定的名称,其作用域与using所在的声明区域相同。using编译指令使名称空间的所有名称可用,如果在全局中使用using编译指令,将使该名称空间中的名称在全局可用,如果在函数定义中使用using编译指令,将会在该函数中该名称空间可用

2、在名称冲突的时候,两者也会有部分差异;例如,名称空间和using声明的区域存在相同的名称,如果在该区域中使用using声明导入名称,则两个名称会发生冲突而出错。如果使用using编译指令,则该区域的局部版本将会隐藏名称空间的版本。using声明的使用比using编译指令要更加安全

(声明会产生冲突(二义性),编译会发生隐藏)

3、名称空间的其他属性

可以将名称空间声明进行嵌套

namespace a

{

        namespace b;

}

也可以在名称空间中使用using声明与using编译指令

namespace a

{

        using std::cout;

        using namespace c;

}

可以给名称空间创建别名

namespace my_very_favorite_things{...};

namespace mvft = namespace my_very_favorite_things;

可以使用这种技术来简化对嵌套名称空间的使用

4、未命名的名称空间

namespace

{

        int a;

        int b;

}

这就像后面跟着using编译指令一样,也就是说,在该名称空间中声明的名称的潜在作用域为:从声明点到该声明区域末尾。从这个方面看,它们与全局变量相似。然而,由于这种名称空间没有名称,因此不能显示的使用using声明和using编译指令来使它在其他位置都可用。具体的说,不能再未命名名称空间所属文件之外的其他文件中,使用该名称空间的名称。这提供了链接性为内部的静态变量的替代品(默认只能在该文件内使用)

6、名称空间用途

1、如果在已命名的名称空间中声明的变量,而不是使用外部全局变量

2、如果在已命名的名称空间中声明的变量,而不是使用静态全局变量

3、如果开发了一个函数库和类库,将其放在一个名称空间中

4、仅将便一直将using作为一种将旧代码转换为使用名称空间的权宜之计

5、不要在头文件中使用using编译指令

6、导入名称时,首选使用作用域解析运算符或using声明的方法

7、对于using声明,首选将其作用域设置为局部而不是全局

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值