C++基础入门:从命名空间到函数重载
C++基础入门:从命名空间到函数重载
- 1. 命名空间
- 1.1 命名空间的定义
- 1.2 命名空间的使用
- 2. C++的输入、输出
- 2.1 基本的输入输出
- 2.2 一些说明
- 3. 缺省参数
- 3.1 缺省参数的概念
- 3.2 缺省参数的分类
- 3.2.1 全缺省参数
- 3.2.2 半缺省参数
- 4. 函数重载
- 4.1 函数重载的基本概念
- 4.2 不能构成重载的情况
- 4.3 原理
- 4.3.1 C 语言不支持函数重载的原因
- 4.3.2 C++支持函数重载的原因
让我们从C++的基础学习开始。先看一个简单的"hello world!"示例代码。虽然这段代码本身看不出C++的全部特性,但随着学习的深入,我们将逐步揭示其独特之处。
//C
#include<stdio.h>
int main() {printf("hello world!");return 0;
}//C++
#include<iostream>
using namespace std; int main() {cout << "hello world!";return 0;
}
简单来说,C++是C的“进化”,它在保留C高性能和底层控制能力的同时,引入了现代编程语言的特性,使得开发大型复杂软件变得更加高效和安全。
1. 命名空间
命名空间 是一种机制,用于将相关的代码(如变量、函数、类等)封装在一个命名的作用域内。它的主要目的是解决命名冲突。
以下是一段C语言代码:
#include<stdio.h>
#include<stdlib.h>int rand = 10;int main()
{printf("%d", rand);return 0;
}//运行会报错
//error: “rand”: 重定义;以前的定义是“函数”
在生成随机数时,也会用到 rand() 这个函数,它包含在stdlib.h头文件中。这看起来时一个小问题,只要更改一下变量名就行。但是在某些大型项目中,多个库或模块可能定义了相同名称的函数或类,编译器将无法区分。所以在C++中就引入了命名空间 —— 一个新的作用域。
1.1 命名空间的定义
命名空间需要使用namespace关键字来定义。
namespace 命名空间名称 {// 命名空间成员声明// 可以包含变量、函数、类、模板、其他命名空间等
}
例:
namespace t1
{int x = 10; //变量void print() //函数{cout << "hello" << endl;}struct node //结构体{int a;int b;};
}namespace t2
{int x = 20;
}namespace t1 //名称与上相同,最终会合并
{int z = 60;
}
在一个工程中可以存在多个名称相同的命名空间,本质上它们都属于同一个命名空间,编译器最后会将它们合并。既然名称相同的命名空间最后都会合并,就要注意不要重命名的问题。
1.2 命名空间的使用
要使用命名空间中的成员,需要使用 ::(作用域解析运算符)。
使用方法如下:
#include<iostream>
using namespace std;
namespace t1
{int x = 10; //变量void print() //函数{cout << "hello" << endl;}struct node //结构体{int a;int b;};
}namespace t2
{int x = 20;
}namespace t1 //名称与上相同,最终会合并
{int z = 60;
}int main()
{//方法1(逐层引用):cout << t1::x << endl;cout << t1::z << endl;t1::print();cout << t2::x << endl;//方法2(引入命名空间名称):using namespace t1;cout << x << endl;cout << z << endl;print();cout << t2::x << endl;//方法3(引入命名空间成员名):using t1::x;using t1::print;cout << x << endl;cout << t1::z << endl;print();cout << t2::x << endl;return 0;
}
以上例子介绍了三种使用方法:
- 逐层引用(命名空间名称 :: 成员名)
- 引入命名空间名称(加入using namespace 空间名称)
- 引入命名空间成员名(加入using 空间成员)
2. C++的输入、输出
2.1 基本的输入输出
- cout(console output):标准输出流对象,用于向控制台输出数据,和 << 配合使用
- cin(console input):标准输入流对象,用于从控制台读取数据,和 >> 配合使用
- endl :换行符,等同于 ‘\n’
#include <iostream>
using namespace std;int main() {int age;//输出cout << "请输入你的年龄: ";//输入cin >> age;//输出cout << "hello" << endl; cout << "你的年龄是:" << age;return 0;
}
运行结果:
请输入你的年龄:20(手动输入)
hello
你的年龄是:20
tips1🌟:与C语言相比,C++的输入输出不需要指定格式符
tips2🌟:C++会自动识别类型,这样就省去了%d,%f 等格式占位符
2.2 一些说明
使用 cout 和 cin 时,要引入名叫 std 的命名空间,std 是 standard(标准)的缩写,它是 C++ 标准库中所有标识符所在的命名空间。
//方法1:
using namespace std;
cout<< "hello" <<endl;//方法2:
using std::cout;
using std::endl;
cout<< "hello" <<endl;//方法3:
std::cout<< "hello" <<std::endl;
因为 std 同样也是一个命名空间,所以三种方法在这里也同样适用。
注意❗️:使用 std 需要头文件 iostream
说明:经过版本的更新,C++中大部分头文件不用带.h
3. 缺省参数
缺省参数,也叫做默认参数,是指在定义函数时,为参数预先指定一个默认值。在调用函数时,如果没有给这个参数传递值,那么函数将自动使用这个默认值;如果传递了值,则使用传递的值。
3.1 缺省参数的概念
以下是最基础的缺省参数:
#include<iostream>
using namespace std;void Func(int a = 6,int b = 8) //缺省参数(默认赋值)
{cout << "a=" << a << " b=" << b << endl;
}int main()
{Func(1,2);Func(); //不传参a b默认为函数形参部分赋的值return 0;
}
运行结果:
a=1 b=2
a=6 b=8
3.2 缺省参数的分类
3.2.1 全缺省参数
全缺省参数是指函数的所有参数都设置了默认值。
#include<iostream>
using namespace std;
void Func(int a = 10, int b = 20, int c = 30) //全部赋默认值
{cout << "a = " << a << " ";cout << "b = " << b << " ";cout << "c = " << c << endl;
}
int main()
{Func(1, 2, 3);Func(1, 2);Func(1); //只能从前开始往后传参(无法跨越)Func();return 0;
}
运行结果:
a = 1 b = 2 c = 3 //Func(1, 2, 3);
a = 1 b = 2 c = 30 //Func(1, 2);
a = 1 b = 20 c = 30 //Func(1);
a = 10 b = 20 c = 30 //Func();
3.2.2 半缺省参数
半缺省参数是指函数的部分参数设置了默认值,而另一部分参数没有设置默认值。
void Func(int a, int b, int c = 30)
{cout << "a = " << a << " ";cout << "b = " << b << " ";cout << "c = " << c << endl;
}
int main()
{Func(1, 2, 3);Func(1, 2);return 0;
}
运行结果:
a = 1 b = 2 c = 3 //Func(1, 2, 3);
a = 1 b = 2 c = 30 //Func(1, 2);
注意❗️:虽然半缺省参数是给部分参数赋值,但也要遵循 从右向左连续 赋值 的原则
4. 函数重载
在 C++ 中,函数重载(Function Overloading)是一个重要的特性,它允许我们在同一作用域内定义多个同名函数,只要它们的参数列表不同即可。下面我来详细讲解函数重载的相关知识。
4.1 函数重载的基本概念
在同一作用域内,可以有一组具有相同函数名但参数列表不同的函数。编译器会根据调用时提供的参数类型和数量来选择最合适的函数版本。
条件:
-
函数名相同
-
参数列表不同
- 参数类型不同
- 参数个数不同
- 参数顺序不同
-
在同一作用域内
#include<iostream>
using namespace std;// 1、参数类型不同
void Func1(int a)
{cout << "(int a)" << endl;
}void Func1(double a)
{cout << "(double a)" << endl << endl;
}//2、参数个数不同
void Func2(int a)
{cout << "a=" << a << endl;
}
void Func2(int a,int b)
{cout << "a=" << a << " b=" << b << endl << endl;
}//3、参数顺序不同
void Func3(int a, char c)
{cout << "a=" << a << " c=" << c << endl;
}
void Func3(char c, int a)
{cout << "a=" << a << " c=" << c << endl << endl;
}int main()
{// 1、参数类型不同Func1(6);Func1(3.6);//2、参数个数不同Func2(7);Func2(8, 10);//3、参数顺序不同Func3(5, 'x');Func3('y', 8);return 0;
}
运行结果:
(int a)
(double a)a=7
a=8 b=10a=5 c=x
a=8 c=y
4.2 不能构成重载的情况
- ❗️仅返回值类型不同
- ❗️参数名不同但类型相同
- ❗️加入了缺省参数
//仅返回类型不同
void err1(int a, int b){……}
int err1(int a, int b){……} //编译器无法区分//参数名不同但类型相同
void err2(int a){……}
void err2(int b){……} //重定义//加入了缺省参数
void err3(int a, int b = 10){……}
void err3(int a){……} //歧义
4.3 原理
这里我们将C和C++做个对比。
4.3.1 C 语言不支持函数重载的原因
在C语言链接过程中,当多个编译单元中存在同名函数时,会导致链接器无法正确区分的问题。
当多个.o目标文件都定义了相同的函数名时,链接器会报告"多重定义"错误,例如:func.c和main.c都定义了void func()
链接时,C 语言只用函数名来查找地址,同名函数无法区分。
4.3.2 C++支持函数重载的原因
C++通过名称修饰(Name Mangling) 技术实现函数重载。编译器会根据函数名和参数列表生成唯一的内部名称。函数重载可通过名称的唯一性实现。
举个例子:
void func(int a)
{cout << a;
}
void func(double a)
{cout << a;
}//编译后可能名称:
void func(int a) ->func_i_
void func(double a) ->func_d_ //名称不同就能够区分
💥:不同编译器的名称修饰规则不同,有兴趣可自行查阅相关资料
