【C++入门指南(上篇)】内含命名空间、缺省参数、函数重载、内联函数等超详细讲解!
C++入门指南(上篇)
嗨,未来的程序员!欢迎来到C++的世界——一个充满力量与创造力的地方。如果你是编程新手,或者刚刚开始学习C++,这篇文章将带你揭开C++的“神秘面纱”。话不多说,我们发车啦!
文章目录
- C++入门指南(上篇)
- 1. C++的第一个程序:Hello world!
- 2. 命名空间: 防止“撞名”的身份证
- 2.1 为什么要有命名空间?
- 2.2 namespac 的定义
- 2.3 命名空间的使用
- 3. C++输入&输出
- 3.1 C++ 的 I/O 库主要包含几个头文件:
- 3.2 标准输入输出
- 4. 缺省参数
- 5. 函数重载
- 结语
1. C++的第一个程序:Hello world!
下面是一个最简单的C++程序:
#include<iostream>usingnamespacestd;intmain(){cout<<"Hello world!"<<endl;return0;}你可能看不懂 namespace std,cout 等,不要担心,下面我们将会详细讲解!
2. 命名空间: 防止“撞名”的身份证
假如你所在的班级有两个“张三”。老师一喊“张三”,俩人同时答应,场面混乱。怎么办?加个限定,比如“高的张三”和“矮的张三”。在C++里,这种“限定”就叫命名空间。
2.1 为什么要有命名空间?
因为C++的库、你写的代码、同事写的代码里,可能会有相同名字的函数或变量(比如大家都想用print做函数名)。命名空间就像“姓氏”,把不同来源的代码隔开,避免冲突。
注意看下面这段代码:
#include<stdio.h>#include<stdlib.h>intrand=10;intmain(){printf("%d\n",rand);return0;}猜猜看这段代码运行会不会报错
答案是:会!!因为rand以前的定义是函数,这里打印就犯了重定义的错误!
那么我们要如何解决这个问题呢?这就要请出namespace了
2.2 namespac 的定义
- 定义命名空间使用关键字namespace,后跟命名空间的名字,然后是一对大括号{ }(注意大括号外没有分号!),里面可以包含变量、函数、类、结构体、甚至另一个命名空间。
namespace本质是定义出一个域,这个域跟全局域各自独立,不同的域可以定义同名变量。- 命名空间只能在全局作用域或其他命名空间内定义,不能在函数内定义。
- 项目工程中多文件中定义的同名namespace会认为是一个
namespace,不会冲突.- C++标准库都放在一个叫std(standard)的命名空间中。
现在就可以重新写一下上面的代码了:
#include<stdio.h>#include<stdlib.h>namespacehj{intrand=10;}intmain(){printf("%p\n",rand);//这里打印出来的是地址,默认访问的//是全局的rand函数指针printf("%d\n",hj::rand);//这里是 hj命名空间中的randreturn0;}输出:
敲黑板:这里使用的::是域作用限定符,符号左边可以写域的名字,如果什么都不写默认去全局域查找,右边写需要查找的内容
命名空间还可以嵌套:
namespacehj{namespacezr{intrand=20;intAdd(intleft,intright){returnleft+right;}}namespacezj{intrand=30;intSub(intleft,intright){returnleft-right;}}}intmain(){printf("%d\n",hj::zr::rand);printf("%d\n",hj::zj::rand);printf("%d\n",hj::zr::Add(2,1));printf("%d\n",hj::zj::Sub(2,1));return0;}输出:
2.3 命名空间的使用
定义好命名空间后,如何访问里面的成员呢?有三种主要方式:
- 作用域限定符 ::
最直接的方式就是使用 ::(作用域解析运算符)来指定成员所属的命名空间。
- using 声明
using 声明 可以将命名空间中的某个特定成员引入当前作用域,之后就可以直接使用该成员的名字。
- using 指令
using 指令 会将整个命名空间中的所有成员都引入当前作用域,之后就可以直接使用该命名空间内的任何成员。
举个例子:
namespacehj{inta=1;intb=2;}intmain(){//指定命名空间访问printf("%d\n",hj::a);return0;}//using 将命名空间中的某个成员引入当前作用域usinghj::b;intmain(){printf("%d\n",hj::a);printf("%d\n",b);}//using 将整个命名空间中的所有成员都引入当前作用域usingnamespacehj;intmain(){printf("%d\n",a);printf("%d\n",b);}重要提示:在实际开发中,尤其是在头文件中,绝对不要使用 using namespace std; 或其他 using 指令,因为头文件会被多个源文件包含,可能导致意想不到的命名冲突。通常只在 .cpp 文件的函数内部或实现文件中局部使用 using 指令。
3. C++输入&输出
3.1 C++ 的 I/O 库主要包含几个头文件:
<iostream>:标准输入输出(cin、cout、cerr、clog)<fstream>:文件输入输出(ifstream、ofstream、fstream)<sstream>:字符串流(istringstream、ostringstream、stringstream)<iomanip>:格式化 I/O 的操纵符(setw、setprecision 等)
3.2 标准输入输出
cout是C++ 最常用的输出对象,它把数据发送到标准输出设备(通常是屏幕)。配合左移运算符 <<,你可以输出各种类型的数据,<< 还可以连续使用。endl与\n
std::endl不仅换行,还会刷新输出缓冲区(强制把数据立即输出)。如果只是换行而不需要立即刷新,可以使用转义字符 \n。cin是标准输入对象,通常从键盘读取数据。使用右移运算符 >>提取数据,可以一次输入多个变量,用空格或回车分隔。cout/cin/endl等都属于C++标准库,C++标准库都放在一个叫std(standard)的命名空间中,所以要通过命名空间的使用方式去用他们。
敲黑板:
cin >>读取字符串时,遇到空白字符(空格、制表符、换行)就会停止。比如输入 “Hello World”,cin >> s 只会得到 “Hello”。- C++的输入输出可以自动识别变量类型,它会根据变量的类型自动选择输出格式(这样写起来会比C语言爽的多!)
- 一般日常练习中我们可以
using namespace std,实际项目开发中不建议使用using namespace std
上代码看看:
#include<iostream>usingnamespacestd;intmain(){inta=1;doubleb=1.1;charc='X';//这两种输出写法效果相同cout<<a<<" "<<b<<" "<<c<<endl;std::cout<<a<<" "<<b<<" "<<c<<endl;cin>>a>>b>>c;//输入数据cout<<a<<" "<<b<<" "<<c<<endl;return0;}效果:
小知识:
在io需求比较高的地方,比如竞赛题中,加上以下3行代码,可以提高C++IO的效率
#include<iostream>usingnamespacestd;intmain(){ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);return0;}4. 缺省参数
- 缺省参数就是在函数声明或定义时,为形参指定一个默认值。这样,在调用函数时,如果省略了该参数,编译器就会自动用默认值代替;如果提供了实参,则用实参覆盖默认值。
- 全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值。这条规则一定要牢记!一旦某个参数有了默认值,它右边的所有参数都必须有默认值。也就是说,默认参数只能放在参数列表的末尾。
- 带缺省参数的函数调用,C++规定必须从左到右依次给实参,不能跳跃给实参。
- 在 C++ 中,函数的声明和定义可以分开。缺省参数通常只放在声明中,不要在定义中重复
那么我们要如何定义缺省参数呢?上代码!
#include<iostream>usingnamespacestd;//全缺省voidFunc1(inta=10,intb=20,intc=30){cout<<"a = "<<a<<endl;cout<<"b = "<<b<<endl;cout<<"c = "<<c<<endl<<endl;}//半缺省voidFunc2(inta,intb=10,intc=20)//这里必须从右往左依次连续缺省{cout<<"a = "<<a<<endl;cout<<"b = "<<b<<endl;cout<<"c = "<<c<<endl;}intmain(){Func1();//不传参数的话会使用默认值Func1(1);//要从左到右依次给实参,这里的1给的是a,//b和c还是使用的默认值Func1(1,2,3);//这里还要注意一下,给半缺省传参时至少要传一个值Func2(4,5,6);}效果:
使用缺省参数有什么好处呢?
- 1. 简化调用:当某个参数在大多数情况下都是同一个值时,就不必每次重复写它。
- 2.扩展功能:可以在不修改已有调用代码的情况下,给函数增加新的参数。只要新参数有默认值,所有旧代码依然能正常工作(因为它们省略了新参数,自动取默认值)。
5. 函数重载
日常生活中,同一个词往往有不同的含义,比如“打”字:可以“打篮球”、“打电话”、“打酱油”……虽然都是“打”,但具体动作完全不同。听的人会根据上下文(后面的词语)自动理解。C++ 中的函数重载就借鉴了这种思想——允许你定义多个同名函数,只要它们的参数列表不同,编译器就会根据调用时传入的参数类型和个数,自动选择合适的版本执行。
函数重载是指在同一个作用域内,可以定义多个同名函数,但它们的参数列表必须不同(参数的个数、类型或顺序不同)。这样,我们就可以用同一个名字表示功能相似但实现细节不同的操作,提高代码的可读性和可维护性。
举几个例子:
#include<iostream>usingnamespacestd;//1.参数类型不同intAdd(intleft,intright)//整型{cout<<"int Add(int left, int right)"<<endl;returnleft+right;}doubleAdd(doubleleft,doubleright)//浮点型{cout<<"double Add(double left, double right)"<<endl;returnleft+right;}intmain(){Add(1,2);Add(1.1,2.2);return0;}效果:
//2.参数个数不同#include<iostream>usingnamespacestd;voidf(){cout<<"f()"<<endl;}voidf(inta){cout<<"f(a)"<<endl;}intmain(){f();f(1);}效果:
//3.参数类型顺序不同#include<iostream>usingnamespacestd;voidf(inta,charb){cout<<"void f(int a, char b)"<<endl;}voidf(charb,inta){cout<<"void f(char b, int a)"<<endl;}intmain(){f(1,'a');f('a',1);}效果:
还要注意返回值类型不同不能作为重载依据!因为调用时无法区分!
#include<iostream>usingnamespacestd;voidf(){//...}intf(){//...return0;}如果两个同名函数一个参数部分有默认值,另一个没有,编译时也会报错!
#include<iostream>usingnamespacestd;//存在歧义,编译器不知道调用谁voidf1(){cout<<"f1()"<<endl;}voidf1(inta=1){cout<<"f1(int a)"<<endl;}结语
现在,你已经解锁了命名空间、输入输出、缺省参数、函数重载、这些“核心技能”,从此写 C++ 不再是天书!
当然,前方还有类、继承、模板、STL 等“高级副本”等着你,但别慌——你已经掌握了最硬核的入门装备。
代码无bug,学习不迷路,我们下篇再见!(•̀ᴗ•́)و
