C++入门(lesson1)

C++入门(lesson1),第1张

目录

一、命名空间(namespace)

1.1命名空间定义

1.2命名空间的使用

①加命名空间名称及域作用限定符

②使用using将命名空间中某个成员引入(命名空间的部分展开或指定展开)

③使用using namespace+命名空间名称引入(命名空间的全部展开)

二、C++输入&输出

2.1详解cout 和 cin

 三、缺省参数

3.1缺省参数概念

 3.2缺省参数分类

①全缺省参数

②半缺省参数

四、函数重载

4.1函数重载概念

①参数类型不同

②参数个数不同

③参数类型顺序不同

4.2函数重载的二义性

①缺省参数导致的二义性

②返回值不同的二义性

4.3 C++支持函数重载的原理

一、命名空间(namespace

在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存 在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化, 以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。

举个例子:

头文件#include中有个rand函数,在C语言中,如果我们不知道这个函数,写了代码,我们会发现,编译器会报错,说是重定义,说明它在库函数中有了定义。如果以后我们写代码都要考虑避免命名冲突,需要记住库里面的命名,显然太麻烦了,而C语言是无法解决类似这样的命名冲突问题,所以C++提出了namespace(命名空间)来解决类似的问题。

1.1命名空间定义

定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{} 中即为命名空间的成员。

比如:

namespace Happy
{
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
		struct Node
	{
		struct Node* next;
		int val;
	};
}

命名空间中可以定义变量、函数、类型等。

命名空间是可以嵌套使用的:

比如:

namespace N1
{
    int a;
    int b;
    int Add(int left, int right)
    {
        return left + right;
    }
    namespace N2
    {
        int c;
        int d;
        int Sub(int left, int right)
        {
            return left - right;
        }
    }
}

注:

1、命名空间只是定义一个域出来,它本身不影响变量的生命周期,它只是一个限定域,编译查找规则。

2、命名空间里的变量等都是全局变量,它们存放在静态区,而非栈,不是像函数一样随着调用结束而终止,它和不在命名空间里的全局变量是一样的,只不过加了限定,防止命名冲突。

3、同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成在同一个命名空间中,同一个文件里相同名称的命名空间也会被合并。可能有的小伙伴会觉得同一个文件的可以理解,同一个工程为什么也会合并呢?这个问题很好解决,在C语言阶段,一个文件中比如test.c包含了test.h的头文件,那么在运行的时候,test.h的内容会直接在test.c文件里展开,所以和同一个文件是类似的。

4、定义到命名空间里的所有内容是无法直接使用的,那么我们如何使用命名空间里的内容呢?

add:补充说明一下命名空间的合并问题,合并仅仅是同级的命名空间才会合并。

比如:

namespace N1
{
	int a = 0;
	namespace N1
	{
		int b = 0;
	}
}

尽管命名相同,但是不会被合并的。

1.2命名空间的使用 ①加命名空间名称及域作用限定符

域作用限定符:就是两个冒号::,如果说命名空间是在全局里开辟一个房间来存放我们定义的一些变量,那么域作用限定符就是那个房间的钥匙,想用房间里的东西,就得用锁打开。

使用范例:

 像这样,我们就可以使用命名空间里的成员。当然,如果仅仅是域作用限定符,前面不加命名空间的话,默认是全局域的。

②使用using将命名空间中某个成员引入(命名空间的部分展开或指定展开

 using就代表使用了这个空间,博主这样的写法意思是仅仅使用命名空间里的a变量,对于像add函数是无权使用的。这种方式也被称为命名空间的部分展开或指定展开

③使用using namespace+命名空间名称引入(命名空间的全部展开)

 当我全部展开的时候,命名空间里的全部内容我都可以当作全局变量使用。

注:日常练习,写一些小程序的时候,全部展开命名空间会非常方便我们写代码,但是,项目里面最好不要这么使用。

二、C++输入&输出

相信大家刚接触C语言的时候是从"hello world"开始的,那也是我们梦开始的地方。那么我们刚接触C++,也是从这里开始,但是这次我们换了一种方式。

#include
using namespace std;
int main()
{
	cout << "Hello world!!!" << endl;
	return 0;
}

说明: 

1.std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中。

2.使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >文件以及按命名空间使用方法使用std.这里我把std全部展开了,否则就得这样编写:

#include
int main()
{
	std::cout << "Hello world!!!" <<  std::endl;
	return 0;
}

3.cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含< iostream >头文件中。

4. <<是流插入运算符,>>是流提取运算符

2.1详解cout 和 cin

cout和printf的较量

 注:

1、博主主要通过cout和printf的对比来说明C++和C,cin和scanf与之类似,就不再赘述,C++和C并不对立,它们是互补,相辅相成的。

2、cout函数是搭配<<使用的,他之所以能够自动识别变量类型,是因为它是一个函数,本质还是C语言封装的。所以这也是为什么printf运行速度要快于cout的。

对于美观的问题:

 我们可以看一下,cout虽然方便,但是不够美观。

最后,对于cout无法实现的类型转换的问题,如果真想转换类型,可以尝试强制转换:

 三、缺省参数 3.1缺省参数概念

缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。

 3.2缺省参数分类 ①全缺省参数

所谓全缺省参数,就是在调用该函数时,没有指定一个实参而全部采用该形参的缺省值。

比如:

void Flower(int a = 66, int b = 88, int c = 99)
{
	cout << "a==" << a << endl;
	cout << "b==" << b << endl;
	cout << "c==" << c << endl;
}
②半缺省参数

比如:

void Flower(int a, int b = 88, int c = 99)
{
	cout << "a==" << a << endl;
	cout << "b==" << b << endl;
	cout << "c==" << c << endl;
}

注意:

1、半缺省参数必须从左往右,依次来给出,不能间隔着给。

void Flower(int a, int b = 88, int c = 99)
{
	cout << "a==" << a << endl;
	cout << "b==" << b << endl;
	cout << "c==" << c << endl;
}
int main()
{
	
	Flower(1);//会给到a值
	Flower(1, 2);//给到a,b值
	Flower(1, 2, 3);//给到a,b,c
	//Func(1, ,2);//间隔着给,不支持
	return 0;
}

2、缺省参数不能在函数声明和定义中同时出现

 像这样,尽管定义和声明设置的缺省参数一致,但编译器依然报错,所以缺省参数不能在函数声明和定义中同时出现,要么都不出现,要么声明或定义一个出现。为什么这么设置呢?

如果生命与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该用哪个缺省值。

3.缺省值必须是常量或者全局变量

这一条说明,我们可以把缺省参数和全局const定义的变量或者宏结合起来使用。

4.缺省参数C语言是不支持的。

四、函数重载 4.1函数重载概念

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

简单来说,函数重载是为了解决一类问题,什么问题呢?非常简单的举个例子,在C语言阶段,我们写一个加法函数,可以解决int类型,而我们要解决double类型的呢?还需要再写一个函数,并且名字还要不同,同样,还有比如要交换两个变量的值,int类型的写一个,double类型的再写一个,名字还要不同显然是很不方便的,因此便有了重载函数的概念。

①参数类型不同
int Add(int left, int right)
{
 cout << "int Add(int left, int right)" << endl;
 return left + right;
}
double Add(double left, double right)
{
 cout << "double Add(double left, double right)" << endl;
 return left + right;
}
②参数个数不同
void f()
{
 cout << "f()" << endl;
}
void f(int a)
{
 cout << "f(int a)" << endl;
}
③参数类型顺序不同
void f(int a, char b)
{
 cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
 cout << "f(char b, int a)" << endl;
}

参数类型顺序不同本质上也是参数类型不同,因为形参的命名是无所谓的。

4.2函数重载的二义性

并不是所有的函数重载都具有二义性的,仅在一些情况下会出现二义性导致出错。

①缺省参数导致的二义性

 我们来看这段代码,出错的原因就在于编译器不知道执行哪个函数,因为我们调用的f()既可以指本身无参的f()函数,也可以指代不传参而使用缺省参数的函数f(int a=0,char b=1).所以才会有对重载函数的调用不明确的报错。

②返回值不同的二义性

相信有小伙伴注意到为什么返回值不同不能作为重载函数呢?

很简单,我们来看以下代码。

 返回值不同是无法区分函数的,因为你传参是一样的,那么传到哪个函数呢?返回的时候返回哪个函数计算的值呢?这些都是不明确的,会导致二义性。

4.3 C++支持函数重载的原理

为什么C++支持函数重载,而C语言不支持函数重载呢?

之前博主有写过C语言预处理的相关内容,我们知道在预处理阶段需要经过预处理->编译->汇编->链接等过程。其中,在链接阶段要进行符号表的合并,符号表中寸的是一些变量,类型,函数等的地址,符合表合并后拿到有效地址。而C语言和C++在链接阶段对于符号表合并后地址的命名是不同的。我们可以来观察以下它们的命名。

 采用C++编译器编译后结果:

 我们通过对比,发现它们的命名是不相同的,在C语言编译器中,对于函数地址的命名是简单的,不考虑参数类型的,而C++是考虑到参数类型不同的,并且不同C++编译器有自己的命名规则,通过参数类型不同,就算函数名相同,命名也是不同的。所以,C++编译器是可以区分相同命名不同形参的函数的,也就是说,这就是它为什么允许函数重载!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/2990670.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-09-23
下一篇 2022-09-23

发表评论

登录后才能评论

评论列表(0条)

保存