【C++进阶之路】初始C++语法(上)

文章目录

  • 前言
  • 一.命名空间
    • 命名冲突
    • 命名空间的使用
      • 展开命名空间
      • 作用域限定符访问
        • 作用域
    • 命名空间的合并
    • 命名空间的嵌套
  • 二.输入输出
    • 打印
      • 流插入运算符
    • 输入
      • 流提取运算符
  • 三.缺省参数
    • 全缺省
    • 半缺省
    • 跨文件缺省函数参数
    • 缺省参数的使用格式
  • 四.函数重载
    • 参数个数不同
    • 参数类型不同
    • 参数顺序不同
    • 注意事项
      • 返回类型不能当做函数重载
      • 参数名不能被当做函数重载
      • 相同类型的缺省参数不是函数重载
    • LInux下的重载函数的符号化

前言

  • 因为C++兼容C的大多数语法,所以我们用C逐步讲解,之后再换成C++语法

一.命名空间

  • 基本概念 : namespace +空间名+{}
  • 切记,最后可没有 ;

命名冲突

#include
#include
int rand = 0;
int main()
{
	printf("%d", rand);
	return 0;
}

编译时,我们会看到:
【C++进阶之路】初始C++语法(上)_第1张图片

  • 结论:与头文件stdlib.h的rand函数的命名冲突了

  • 问题:不改变此变量的名字的前提下,如何正确打印此变量?

  • 答案: 使用命名空间将变量进行封装

注意:命名空间的名字也会发生命名冲突,因此不要起rand!

#include
#include
namespace shunhua
{
	int rand = 0;
}
int main()
{
	printf("%d", rand);
	return 0;
}
  • 这样就对了吗?
  • 其实不对。

这里其实识别的是rand函数,不是命名空间里的变量!

  • 因此:命名空间是将变量或者函数封装,因此是无法直接访问的!

命名空间的使用

展开命名空间

  • using namespace + 空间名+ ;
    接着上文
#include
#include
namespace shunhua
{
	int rand = 0;
}
using namespace shunhua;
int main()
{
	printf("%d", rand);
	return 0;
}

再次编译,看结果
在这里插入图片描述

  • 这是怎么回事呢?
  • 答案 :使用命名空间,相当于将命名空间暴露与全局范围中,因此又回到了我们要最初要解决的问题。
    • 命名冲突打印指定变量
  • 接着往下讨论

作用域限定符访问

作用域

学过C语言,想必都能看懂这一段代码。

#include
int rand = 1;
int main()
{
	int rand = 0;
	printf("%d\n", rand);
	return 0;
}
  • 全局变量与局部变量同名时,优先使用局部变量
  • 换到C++,域是查找变量的默认优先顺序:
  • 1.局部域
  • 2.全局域
  • 3.命名空间访问变量用——展开的命名空间/限定符访问。

作用域限定符:

: :前面要不加默认使用全局变量,前面加命名空间使用的是命名空间的变量

#include
namespace shun_hua
{
	int rand = 3;
}
int rand = 1;
int main()
{
	int rand = 0;
	printf("%d\n", rand);//局部变量中查找
	printf("%d\n",::rand);//全局域里面查找
	printf("%d\n",shun_hua::rand);//在命名空间里面查找
	return 0;
}

执行结果:
【C++进阶之路】初始C++语法(上)_第2张图片
回头解决要解决的问题:

#include
#include
namespace shunhua
{
	int rand = 0;
}
int main()
{
	printf("%d", shunhua::rand);
	return 0;
}

此时再编译没问题,执行一下:
【C++进阶之路】初始C++语法(上)_第3张图片
成功打印出命名空间的值

  • 命名冲突打印指定变量

命名空间的合并

  • 当我们多次定义同名空间时,相当于定义了一个命名空间同名的命名会自动将变量与函数进行合并,而不是我们想的重命名!
#include
#include
namespace shun_hua
{
	int rand = 0;
	int y = 1;
}
namespace shun_hua
{
	int x = 2;
	int z = 3;
}
int main()
{
	printf("%d\n", shun_hua::rand);
	printf("%d\n", shun_hua::x);
	printf("%d\n", shun_hua::y);
	printf("%d\n", shun_hua::z);
	return 0;
}
  • 这里面的命名空间在合并时,是不允许出现相同的函数或变量出现两次的,如果有会直接在语法上,报错。也就是说命名空间的合并是在编译阶段完成的!
  • 如果需要在一个命名空间里面出现两个相同变量怎么办呢?
  • 命名空间的嵌套

命名空间的嵌套

  • 1.命名空间的嵌套是可以使用相同名字的。
  • 2.这样展开命名空间编译器会不知道展开哪个,从而报错
#include
namespace shun_hua
{
	int x = 0;
	namespace shun_hua
	{
		int x = 1;
	}
}
//using namespace shun_hua;
int main()
{
	printf("%d\n", shun_hua::shun_hua::x);
	return 0;
}

输出结果:
【C++进阶之路】初始C++语法(上)_第4张图片

二.输入输出

我们首先要明白C++库的基本结构
【C++进阶之路】初始C++语法(上)_第5张图片

  • 因此C++库是被封装在std命名空间里面的,使用C++库里的对象得通过std访问。
  • C++包含头文件是不需要后缀.h
  • 输入输出文件在iostream的头文件中

拓展: 早期的头文件在全局域中实现,因此头文件含.h, 后来为了与C头文件区分以及正确的使用命名空间声明C++的头文件不带.h,因此我们现在看到的iostream不带头文件,而在早期的VC6.0版本还可以使用iostream.h的版本。

打印

流插入运算符

<<跟C语言的左移操作符意义不同,这里是流插入运算符,将数据流入输出流。

打印hello world

#include//包含头文件
using namespace std;//使用命名空间,这两者缺一不可
int main()
{
	cout << "hello world\n";
	return 0;
}

我们一般看到的写法是这样的

#include//包含头文件
using namespace std;//使用命名空间,这两者缺一不可
int main()
{
	cout << "hello world"<<endl;//这里的endl其实就是"\n"
	return 0;
}
  • 我们不推荐这样使用命名空间,因为这样将std的命名空间暴露在全局域中, 失去了命名空间创建的意义。
    一般推荐这样写
#include//包含头文件
using std::cout;
using std::endl;
//这其实是我们使用命名空间的符号的声明
int main()
{
	cout << "hello world"<<endl;
	std::cout<<"hello world"<<std::endl;
	//在使用时也可以这样写,不过在重复多次写这里语句时,比较麻烦。
	return 0;
}

输入

流提取运算符

  • > >与C语言的右移操作符不同,这里是流提取,将数据输进输入流

输入一个整形,并将这个整形打印

#include
using std::cin;
using std::cout;
using std::endl;
int main()
{
	int x = 0;
	cin >> x;//这是将输入流的数据读取出来放进x
	cout << x << endl;
	return 0;
}
  • 总结:cout和cin会自动识别类型,不像printf和scanf需要手动的控制其类型,因此还是比较方便的。

三.缺省参数

  • 缺省参数,是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参
  • 也就是说在函数的指定参数有默认值的情况下,调用函数时,指定参数可以传参,也可不传,即为缺省

全缺省

  • 函数的定义或者声明时,函数的参数都有默认值
#include
using std::cout;
using std::endl;
int add(int x = 0 ,int y = 0)
{
	return x + y;
}
int main()
{
	cout << add() << endl;
	cout << add(1,2) << endl;
	cout << add(1) << endl;
	//cout<
	//语法规定不行
	return 0;
}
  • 函数缺省,调用时,从左往右进行传参,且从左往右是与函数的参数一 一对应,不能省略的。

半缺省

  • 半缺省指的是一部分参数缺省,缺省参数只能从右往左进行缺省
  • 注意: 可不是一半的参数缺省
#include
using std::cout;
using std::endl;
int add(int x, int y = 0)
{
	return x + y;
}
int main()
{
	cout << add(1) << endl;
	cout << add(1, 2) << endl;
	return 0;
}
  • 用途:在单链表初始化时,可以指定开辟大小,也可以指定默认参数。

跨文件缺省函数参数

【C++进阶之路】初始C++语法(上)_第6张图片
add.h文件

int add(int x = 0,int y = 0);

add.cpp文件

#include"add.h"
int add(int x, int y)
{
	return x + y;
}

test.cpp文件

#include"add.h"
#include
using std::cout;
using std::endl;
int main()
{
	cout<<add(1)<<endl;
	cout << add(1,2) << endl;
	return 0;
}
  • 情况:缺省参数的函数定义与声明在不同文件中
  • 在函数声明中需声明缺省参数,**定义则不用写缺省参数,**否则会出现重定义。
  • 原因:头文件的函数声明,在编译期间就会被识别,相当于先给编译器一个承诺,函数是什么样子的,而函数定义是在链接期间被检查的,因此声明时前提(承诺),定义是结果(无需写缺省参数)。

缺省参数的使用格式

  • 缺省参数只能用常量或者具有全局属性的变量
#include
using std::cout;
using std::endl;
#define MAX 100//常量
int x = 0;//全局变量
int add(int max = MAX, int min = x)
{
	return max+min;
}
int main()
{
	cout << add() << endl;
	return 0;
}

四.函数重载

  • 重载,顾名思义就是一词多义,比如比如:以前有一个笑话,国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个是男足。前者是“谁也赢不了(乒乓)!”,后者是“(国足)谁也赢不了!”。

  • 函数重载就是函数同名不同义。

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

参数个数不同

#include
using std::cout;
using std::endl;
int add()
{
	return 0;
}
int add(int x)
{
	return x;
}
int main()
{
	cout << add() << endl;
	cout << add(1) << endl;
}

参数类型不同

#include
using std::cout;
using std::endl;
int add(int x ,int y)
{
	return 0;
}
int add(double x,double y)
{
	return 0;
}
int main()
{
	cout << add(1,1) << endl;
	cout << add(1.0,1.0) << endl;
}

参数顺序不同

#include
using std::cout;
using std::endl;
int add(int x ,double y)
{
	return 0;
}
int add(double y,int x)
{
	return 0;
}
int main()
{
	cout << add(1,1.0) << endl;
	cout << add(1.0,1) << endl;
}

注意事项

返回类型不能当做函数重载

  • 函数重载是指的函数调用,所发生的类型识别和参数个数,从而确定调用哪个同名函数,而函数的返回值是不能根据函数调用进行确定的

示例:

  • 首先说明此代码会报错,原因是在函数调用时,不能区分返回类型,因此调用存在歧义。
#include
using std::cout;
using std::endl;
int add(int x ,int y)
{
	return 0;
}
float add(int x,int y)
{
	return 0;
}
int main()
{
	cout << add(1,0) << endl;
	cout << add(1,1) << endl;
}

编译结果:
在这里插入图片描述

参数名不能被当做函数重载

#include
using std::cout;
using std::endl;
int add(int x ,int y)
{
	return 0;
}
int add(int y,int x)
{
	return 0;
}

编译结果:
【C++进阶之路】初始C++语法(上)_第7张图片

相同类型的缺省参数不是函数重载

示例:

#include
using std::cout;
using std::endl;
int add(int x ,int y = 0)
{
	return 0;
}
float add(int x,int y)
{
	return 0;
}

编译结果:
在这里插入图片描述

LInux下的重载函数的符号化

Linux下gcc编译的结果
【C++进阶之路】初始C++语法(上)_第8张图片

  • 结论:函数符号化为函数本身的名字
    Linux下g++编译的结果
    【C++进阶之路】初始C++语法(上)_第9张图片

  • g++编译的生成的函数符号名的规则:_Z+函数名长度+函数名+参数类型的首字母

  • 总结:C++本身其实不是通过函数名进行查找,而是通过函数符号化之后的结果,访问地址从而调用函数。

你可能感兴趣的:(C++进阶之路,c++)