之前浅显的讲解了数据结构的部分内容:数据结构专栏
那么今天我们迎来了新的起点:C++的探索之旅
文章目录
- 1.命名空间
- 1.1引入命名冲突
- 1.2命名空间
- 1.2.1命名空间的定义
- 1.2.2命名空间的使用
- 2.c++的输入与输出
- 3.缺省参数
- 3.1概念
- 3.2缺省参数分类
- 4.函数重载
- 4.1概念
- 4.2C++支持重载的原理----名字修饰
1.命名空间
1.1引入命名冲突
在c中:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//定义一个全局变量
int rand = 1;
int main()
{
srand(time(0));
printf("%d\n", rand);
return 0;
}
严格的编译器会直接报错:
rand我们都知道是产生随机数的函数,现在我定义了一个全局变量rand,显然是有命名冲突
所以c++就提供了解决方案
1.2命名空间
想必学过c的大家第一次接触c++看到:
using namespace std;
都会想这是什么??大多老师都会让说:你们先记着这是固定的,以后会懂(结果到了期末考完也什么都没说)
namespace
是 C++ 中的关键字,用于创建命名空间,它是用来避免命名冲突并组织代码的一种机制。通过命名空间,可以将一系列的变量、函数、类等内容封装在其中,以便更好地组织代码
1.2.1命名空间的定义
定义命名空间,需要使用到
namespace
关键字,后面跟命名空间的名字,然后接一对{ }
即可,{ }
中即为命名空间的成员
- 命名空间的定义事例
namespace Test1 { // 命名空间中可以定义变量/函数/类型... int rand = 1; int Add(int left, int right) { return left + right; } struct ListNode { struct Node* next; int data; }; }
- 命名空间可以嵌套
namespace Test2 { int a = 0; namespace Test2_1 { int a = 1; } }
- 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中(合并成一个)
一个工程中的test.h和上面test.cpp中两个N1会被合并成一个命名空间
一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中
1.2.2命名空间的使用
双冒号
::
在 C++ 中是作用域解析运算符,它用于指定特定范围内的命名空间或类的成员。它的主要作用有两个:
- 命名空间限定:用于指定特定命名空间中的变量、函数或类。例如,
std::cout
中的std
是命名空间,cout
是该命名空间下的对象。- 类作用域限定:用于指定类的成员函数或静态成员变量。在类的定义或类外部,双冒号可以用于访问类的静态成员
命名空间的使用有三种方式:
- 加命名空间名称及作用域限定符
namespace Test1
{
// 命名空间中可以定义变量/函数/类型...
int rand = 1;
int Add(int left, int right)
{
return left + right;
}
}
int main()
{
// 使用作用域限定符号直接访问命名空间中的成员
printf("%d\n", Test1::rand);
return 0;
}
成功输出了:
- 使用using将命名空间中某个成员引入
namespace Test2
{
int b = 0;
namespace Test2_1//这里命名空间嵌套
{
int a = 1;
}
}
using Test2::b;
int main()
{
printf("%d\n", b);
printf("%d\n",Test2:: Test2_1::a);//这样访问a
return 0;
}
- 使用using namespace 命名空间名称引入
这就是我们经常看到的using namespace std;
使用后使用std命名空间时就不需要加上std::
,可以直接用了
2.c++的输入与输出
#include<iostream>
// std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
//(直接 using namespace std有点不安全)
using namespace std;
int main()
{
int a = 0;
cin >> a;
cout << a << endl;
cout << "Hello world!!!" << endl;
return 0;
}
- 使用
cout
标准输出对象(控制台)和cin
标准输入对象(键盘)时,必须包含< iostream >头文件
以及按命名空间的使用方法使用std。cout
和cin
是全局的流对象,endl
是特殊的C++符号,表示换行输出,他们都包含在包含< iostream >头文件
中。<<
是流插入运算符,>>
是流提取运算符。(cout<<
就是流入到控制台 )- 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。C++的输入输出可以自动识别变量类型。
- 实际上cout和cin分别是ostream和istream类型的对象,>>和<<也涉及运算符重载等知识(挖个坑,以后详细介绍)
3.缺省参数
3.1概念
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参
void Function1(int a = 0)
{
cout<<a<<endl;
}
int main()
{
Func(); // 没有传参时,使用参数的默认值
Func(10); // 传参时,使用指定的实参
return 0;
}
3.2缺省参数分类
- **全缺省参数(函数声明或定义中都指定默认值)
void Function2(int a = 1, int b = 2, int c = 3)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
}
- 半缺省参数
void Function3(int a, int b = 2, int c = 3)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
}
注意:
- 半缺省参数必须从右往左依次来给出,不能间隔给
- 缺省参数不能在函数声明和定义中同时出现,有函数声明一般选择函数声明
- 缺省值必须是常量或者全局变量
4.函数重载
学过Java的同学必然不陌生
4.1概念
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表==(参数个数或类型或类型顺序)==不同,常用来处理实现功能类似数据类型不同的问题。
- 函数参数类型不同
int Add(int a, int b)
{
return a + b;
}
double Add(double a, double b)
{
return a + b;
}
int main()
{
cout<<Add(10, 20)<<endl;
cout<<Add(10.1, 20.2);
return 0;
}
- 函数参数个数不同
void f()
{
cout << "f()" << endl;
}
void f(int a)
{
cout << "f(int a)" << endl;
}
- 函数参数类型顺序不同(也可认为属于类型不同)
void f(int a, char b)//先int后char
{
cout << "f(int a,char b)" << endl;
}
void f(char b, int a)//先char后int
{
cout << "f(char b, int a)" << endl;
}
4.2C++支持重载的原理----名字修饰
在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接
链接器看到Test.o调用某个函数,但是没有函数的地址,就会到Func.o的符号表中找函数的地址,然后链接到一起。而使用哪个名字去找呢?这里每个编译器都有自己的函数名修饰规则
c语言链接函数地址时(找函数)是靠函数名,所以不允许重名函数
c++中编译器需要为每个函数生成一个唯一的标识符来标记函数的地址。在 Linux 下,这些标识符是通过一种名为名字修饰(Name Mangling)的方式来生成的:
_Z + 函数名字符个数 + 函数名 + 每个参数类型首字母
所以重载函数虽然函数名相同,但是在链接函数地址时所依靠的标识符却不同
- 通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。
- 如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分
今天步入c++的学习啦,就先到这里!!!