目录
  • 命名空间的使用
    • 来源
    • 命名空间的使用
      • 不展开
      • 部分展开
      • 全展开
    • 函数重载
      • 函数重载的规则
      • C++如何实现函数重载
  • 引用

    命名空间的使用

    来源

    在了解命名空间的原理和使用之前,我们先要理解,命名空间是为了解决什么问题。

    C++是在C的基础上发展而形成的一种语言,完全兼容C的语法,也加入了许多新的规则和语法来解决C的缺陷。

    命名空间就是为了解决C语言中的重复命名的问题。

    首先我们来看看这么一个代码:

    #include<stdio.h>
    int main()
    {
    	int scanf = 20;
    	printf("%d", scanf);
    	return 0;
    }

    我们都知道scanf在C之中是一个函数名,但诡异的是我们在主函数中声明scanf是有效的并且输出结果是20.

    C++超详细梳理基础知识

    在这个程序内的scanf就是表示是一个int型整数,这是根据就近原则或者说是局部优先原则确定的。

    接下来我们看看另一个程序:

    #include<stdio.h>
    int main()
    {
    	int scanf = 20;
    	scanf("%d", &scanf);
    	printf("%d", scanf);
    	return 0;
    }

    在我们想要scanf作为函数使用时出现了问题,两者之间命名冲突。

    在C语言中我们被告诫不要让变量名与函数名冲突,但是在C++中有没有合适的解决方法呢?

    命名空间的使用

    我们先来书写一个在C++中最为简单的程序:

    #include<iostream>
    using namespace std;
    int main()
    {
    	cout << "hello  world" << endl;
    	return 0;
    }

    这里我们就看到了namespace命名空间,但是现在它是用来干什么的我们还不清楚,首先我们先来了解一下它。

    一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中。

    让我们从代码方面来看看命名空间到底是什么:

    #include<iostream>
    using namespace std;
    namespace  N1
    {
    	int printf = 30;
    	int strlen = 20;
    }
    int main()
    {
    	cout << "hello  world" << endl;
    	cout << N1::printf << endl;
    	return 0;
    }

    我们声明了一个命名空间N1,在内部声明了两个int类型的变量,通过作用域限定符::我们就可以调用命名空间中的变量。

    并且命名空间中也可以嵌套命名空间:

    namespace  N1
    {
    	int printf = 30;
    	int strlen = 20;
    	namespace  N2
    	{
    		int a = 0;
    	}
    }

    通过上面的解释,我们明白了,命名空间适用于将声明的名称之间相互隔离,防止命名冲突。比如说,我们调用N1::printf时,::将范围限定在N1这个命名空间之中,而不会与函数名printf冲突,反之亦然。

    那么一开始我们看到的那个程序是什么意思呢?

    我们先来看另一个版本的程序:

    int main()
    {
    	std::cout << "hello  world" << std::endl;
    	//cout << N1::printf << endl;
    	return 0;
    }

    显然std也是一个命名空间,通过作用域限定符调用命名空间std内的内容。

    那么一开始的

    using namespace std;

    是用来干嘛的呢?

    using的作用是把命名空间中的内容在全局空间中展开,命名空间中的变量就成为了全局变量,调用时就不需要命名空间名加上作用域限定符了。

    实际上命名空间有三种使用方式,各有优劣。

    不展开

    也就是

    std::cout << "hello  world" << std::endl;

    的方式,要使用命名空间中的名称,就要使用::来限定命名空间,完全避免了冲突,在大工程中使用。缺点就是在日常练习中书写代码较为繁琐。

    部分展开

    使用using将命名空间中成员引入,将一些我们常用的符号在全局中展开,就可以大大简化代码,是在第一个方法和第三个方法之间取一个折中。

    using std::cout;
    using std::endl;
    int main()
    {
    	cout << "hello  world" << endl;
    	//cout << N1::printf << endl;
    	return 0;
    }

    全展开

    使用using namespace 命名空间名称引入:

    using namespace std;
    int main()
    {
    	cout << "hello  world" << endl;
    	//cout << N1::printf << endl;
    	return 0;
    }

    这个方法是有问题的,相当于一夜回到解放前。好不容易搞个命名空间隔离了,结果一行代码全给展开了,直接在全局空间声明,完全没有防止命名冲突的作用,只在日常练习中使用。

    函数重载

    函数重载的规则

    自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了。

    比如:以前有一个笑话,国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个是男足。前者是“谁也赢不了!”,后者是“谁也赢不了!”

    函数重载是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数 个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题。

    比如下面的相加函数:

    int Add(int left, int right)
    {
    return left+right;
    }
    double Add(double left, double right)
    {
    return left+right;
    }
    long Add(long left, long right)
    {
    return left+right;
    }
    int main()
    {
    Add(10, 20);
    Add(10.0, 20.0);
    Add(10L, 20L);
    return 0;
    }

    虽然函数名相同,但是所带参数的类型不同,所以在调用的时候能够调用不同的函数定义,让函数的使用更加灵活。

    这里要特别注意的是函数重载的规则:同名函数的形参列表(参数 个数 或 类型 或 顺序)必须不同。

    short Add(short left, short right)
    {
    return left+right;
    }
    int Add(short left, short right)
    {
    return left+right;
    }

    那么两个同名函数,算不算是函数重载呢,显然他们的形式参数的个数 ,类型以及 顺序都是一样的,只是返回类型不同,不构成重载函数。

    C++如何实现函数重载

    我们都知道C是没有函数重载这个功能的,那么C++是怎么实现的呢?

    其实是通过C++的函数名修饰来实现函数重载的。

    大家这里可能有一些迷糊,这需要我们对代码的编译过程有一定的了解:

    C++超详细梳理基础知识

    C和C++的区别在于,在编译的符号汇总中,C语言是使用函数的原名进行汇总的,导致了一个名称只能对应一个函数,所以不能进行函数重载。

    但是在C++中,符号汇总起来的是经过修饰的函数名,即使原名称一样,由于参数 个数 或 类型 或 顺序不同,经过修饰后的符号名也不同,比如说:

    int Add(int left, int right)
    {
    return left+right;
    }
     
    double Add(double left, double right)
    {
    return left+right;
    }
     
    long Add(long left, long right)
    {
    return left+right;
    }

    比如说这三个函数经过函数名修饰之后就变成了——Addii、Adddd、Addll。于是我们在后续的使用中就可以很好地区分这三个函数了,即使在我们看来这三个函数名是一样的,但是在计算机看来这三个完全就是三个不一样的函数。

    引用

    引用可以说就是给变量取别名。是怎么实现的呢?

    #include<iostream>
    int main()
    {
    	int a = 0;
    	int b = 0;
    	int& c = a;
    	c = 10;
    	return 0;
    }

    其中 int& c = a; 就是把c作为a的别名,这时c和a指向的内存空间是同一块。

    C++超详细梳理基础知识

    当改变c的值时,a中的值同时改变。

    C++超详细梳理基础知识

    但是,在使用过程中也有一些需要注意的事项——

    1.引用类型必须和引用实体是同种类型的

    C++超详细梳理基础知识

    C++超详细梳理基础知识

    2.引用在定义时必须初始化

    int a;
    int& b = a;

    C++超详细梳理基础知识

    3.一个变量可以有多个引用

    int a = 0;
    int& b = a;
    int& c = a;
    int$ d = c;

    4.引用一旦引用一个实体,再不能引用其他实体

    #include<iostream>
    int main()
    {
    	int a = 0;
    	int b = 0;
    	int& c = a;
    	int& c = b;
    	c = 10;
    	return 0;
    }

    C++超详细梳理基础知识

    声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。