跳到主要内容 C++ 基础知识入门:命名空间、引用与函数重载 | 极客日志
C++ 算法
C++ 基础知识入门:命名空间、引用与函数重载 系统讲解 C++基础知识,包括首个程序的编写、命名空间的定义与作用、标准输入输出流的使用、缺省参数规则、函数重载机制、引用的概念与特性、内联函数的优化原理以及 nullptr 关键字的正确用法。通过代码示例和对比分析,帮助读者理解核心语法并避免常见错误。
虚拟内存 发布于 2026/3/30 更新于 2026/4/13 1 浏览C++ 入门基础
1. C++的第一个程序
#include <iostream>
using namespace std;
int main () {
cout << "Hello World" << endl;
return 0 ;
}
2. 命名空间
2.1 namespace 的价值
在 C/C++ 中,变量、函数和类大量存在,名称都存在于全局作用域中,可能会导致冲突。命名空间的目的是对标识符进行本地化,以避免命名冲突,namespace关键字的出现就是针对这种问题的。
2.2 namespace 的定义
定义命名空间需要使用 namespace关键字,后面跟命名空间的名字,然后接一对 {}即可,{}中即为命名空间的成员,可以定义变量、函数、类型等。
namespace本质是定义一个域,这个域跟全局域各自独立,不同的域可以定义同名变量。
C++中域有函数局部域、全局域、命名空间域、类域;域影响的是编译时语法查找一个变量/函数/类型出处的逻辑。
namespace只能定义在全局,当然它还可以嵌套定义。
项目工程中多文件中定义的同名 namespace会认为是同一个 namespace,不会冲突。
C++标准库都放在一个叫 std(standard)的命名空间中。
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
namespace abc {
int rand = 10 ;
int Add (int left, int right) {
return left + right;
}
struct Node {
* next;
val;
};
}
{
( , rand);
( , abc::rand);
;
}
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown 转 HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
HTML 转 Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
struct
Node
int
int main ()
printf
"%p\n"
printf
"%d\n"
return
0
namespace asd {
namespace aaa {
int rand = 15 ;
}
namespace bbb {
int rand = 20 ;
}
}
int main () {
printf ("%d\n" , asd::aaa::rand);
printf ("%d\n" , asd::bbb::rand);
return 0 ;
}
2.3 命名空间使用 编译查找一个变量的声明/定义,默认只会在局部或者全局查找,不会到命名空间里去查找。所以我们要使用命名空间中定义的变量/函数,有三种方式:
指定命名空间,项目中推荐这种方式。
using将命名空间中某个成员展开,项目中经常访问的,不存在冲突的成员推荐这种方式。
展开命名空间中全部成员,项目不推荐,冲突风险大,日常练习程序为了方便推荐使用。
namespace N {
int a = 0 ;
int b = 0 ;
}
int main () {
printf ("%d\n" , N::a);
return 0 ;
}
using N::b;
int main () {
printf ("%d\n" , N::a);
printf ("%d\n" , b);
return 0 ;
}
using namespace N;
int main () {
printf ("%d\n" , a);
printf ("%d\n" , b);
return 0 ;
}
3. C++输入&输出
是 Input Output Stream 的缩写,是标准的输入、输出流库,定义了标准的输入、输出对象。
std::cin是 istream类的对象,它主要面向窄字符的标准输入流。
std::cout是 ostream类的对象,它主要面向窄字符的标准输出流。
std::endl是一个函数,流插入输出时,相当于一个换行符加刷新缓冲区。
<<是流插入运算符,>>是流提取运算符。
C++输入输出不需要像 printf/scanf输入输出那样指定格式,C++输入输出可以自动识别变量类型。
cout/cin/endl等都属于 C++标准库,C++标准库都放在 std命名空间中,所以要通过命名空间的使用方式使用它们。
一般练习中我们可以使用 using namespace std,实际项目开发中不建议。
#include <stdio.h>
using namespace std;
int main () {
int a = 0 ;
double b = 0.1 ;
char c = 'x' ;
cout << a << " " << b << " " << c << endl;
std::cout << a << b << c << std::endl;
scanf ("%d%lf\n" , &a, &b);
printf ("%d %lf\n" , a, b);
return 0 ;
}
在 IO 需求比较高的地方(如大部分大量输入的竞赛题中),加以下 3 行代码,可以提高效率:
ios_base::sync_with_stdio (false );
cin.tie (nullptr );
cout.tie (nullptr );
4. 缺省参数
缺省参数是声明或定义时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。缺省参数分为全缺省和半缺省参数。
全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值。
带缺省参数的函数调用,C++规定必须从左到右依次给实参,不能跳跃给实参。
函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值。
#include <iostream>
#include <assert.h>
using namespace std;
void Func (int a = 0 ) {
cout << a << endl;
}
int main () {
Func ();
Func (10 );
return 0 ;
}
#include <iostream>
using namespace std;
void Func1 (int a = 10 , int b = 20 , int c = 30 ) {
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl << endl;
}
void Func2 (int a, int b = 10 , int c = 20 ) {
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl << endl;
}
int main () {
Func1 ();
Func1 (1 );
Func1 (1 , 2 );
Func1 (1 , 2 , 3 );
Func2 (100 );
Func2 (100 , 200 );
Func2 (100 , 200 , 300 );
return 0 ;
}
5. 函数重载 C++支持在同一作用域中 出现同名函数 ,但是要求这些同名函数的形参不同,可以是参数个数不同或者类型不同。这样 C++函数调用就表现出了多态行为,使用更灵活。C语言是不支持同一作用域中出现同名函数的。
#include <iostream>
using namespace std;
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;
}
int main () {
Add (10 , 20 );
Add (10.1 , 20.2 );
f ();
f (10 );
f (10 , 'a' );
f ('a' , 10 );
return 0 ;
}
6. 引用
6.1 引用的概念和定义 引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
类型& 引用别名 = 引用对象
#include <iostream>
using namespace std;
int main () {
int a = 0 ;
int & b = a;
int & c = a;
int & d = b;
++d;
cout << &a << endl;
cout << &b << endl;
cout << &c << endl;
cout << &d << endl;
return 0 ;
}
6.2 引用的特性
引用在定义时必须初始化
一个变量可以有多个引用
引用一旦引用一个实体,就不能引用其他实体
#include <iostream>
using namespace std;
int main () {
int a = 10 ;
int & b = a;
int c = 20 ;
cout << &a << endl;
cout << &b << endl;
cout << &c << endl;
return 0 ;
}
6.3 引用的使用
引用在实践中主要是用于引用传参和引用做返回值中减少拷贝提高效率和改变引用对象时同时改变被引用对象。
引用传参跟指针传参功能是类似的,引用传参相对更方便一些。
引用和指针在实践中相辅相成,功能有重叠性,但是各有特点,互相不可替代。C++的引用跟其他语言的引用是有很大的区别的,除了用法,最大的点,C++引用定义后不能改变指向。
void Swap (int & rx, int & ry) {
int tmp = rx; rx = ry; ry = tmp;
}
int main () {
int x = 0 , y = 1 ;
cout << x << " " << y << endl;
Swap (x, y);
cout << x << " " << y << endl;
return 0 ;
}
6.4 const 引用
可以引用一个 const 对象,但是必须用 const 引用。const 引用也可以引用普通对象,因为对象的访问权限在引用过程中可以缩小,不能放大。
不过需要注意的是类似 int& rb = a*3; double d = 12.34; int& rd = d; 这样一些场景下 a*3的结果保存在一个临时对象中,int& rd = d也是类似,在类型转换中会产生临时对象存储中间值,也就是,rb 和 rd 引用的都是临时对象,而 C++规定临时对象具有常性,所以这里就触发了权限放大,必须要用常引用才可以。
所谓临时对象就是编译器需要一个空间暂存表达式的求值结果临时创建一个未命名对象,C++中把这个未命名对象叫做临时对象。
#include <iostream>
using namespace std;
int main () {
const int a = 10 ;
const int & ra = a;
int b = 20 ;
const int & rb = b;
return 0 ;
}
int main () {
int a = 10 ;
const int & ra = 30 ;
const int & rb = a * 3 ;
double d = 12.34 ;
const int & rd = d;
return 0 ;
}
6.5 指针和引用的关系 C++中指针和引用就像两个性格迥异的亲兄弟,指针是哥哥,引用是弟弟,在实践中他们相辅相成,功能有重叠性,但是各自有各自特点,互相不可替代。
语法概念上引用是一个变量的取别名不开空间,指针是存储一个变量地址,要开空间。
引用在定义时必须初始化,指针建议初始化,但是语法上不是必须的。
引用在初始化时引用一个对象后,就不能再引用其他对象;而指针可以在不断地改变指向对象。
引用可以直接访问指向对象,指针需要解引用才是访问指向对象。
sizeof 中含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占字节个数 (32 位平台下,64 位下是 8byte)。
指针很容易出现空指针和野指针的问题,引用很少出现,引用使用起来相对更安全一些。
7. inline
inline修饰的函数叫做内联函数,编译时 C++编译器会在调用的地方展开内联函数,这样调用内联函数就不需要建立栈帧了,就可以提高效率。
inline对于编译器而言只是一个建议,也就是说,你加了 inline编译器也可以选择在调用的地方不展开,不同编译器关于 inline什么情况展开各不相同,因为 C++标准没有规定这个。inline适用于频繁调用的短小函数,对于递归函数,代码相对多一些的函数,加上 inline也会被编译器忽略。
C语言实现宏函数也会在预处理时替换展开,但是宏函数实现很复杂很容易出错的,且不方便调试,C++设计了 inline目的就是替代 C 的宏函数。
vs 编译器 debug 版本下面默认是不展开 inline的,这样方便调试,debug 版本想展开需要设置下以下两个地方。
inline不建议声明和定义分离到两个文件,分离会导致链接错误。因为 inline被展开,就没有函数地址,链接时会出现报错。
#include <iostream>
using namespace std;
inline int Add (int x, int y) {
int ret = x + y; ret += 1 ; ret += 1 ; ret += 1 ;
return ret;
}
int main () {
int ret = Add (1 , 2 );
cout << Add (1 , 2 ) * 5 << endl;
return 0 ;
}
#include <iostream>
using namespace std;
int main () {
int ret = ADD (1 , 2 );
cout << ADD (1 , 2 ) << endl;
cout << ADD (1 , 2 ) * 5 << endl;
int x = 1 , y = 2 ;
ADD (x & y, x | y);
return 0 ;
}
#include <iostream>
using namespace std;
inline void f (int i) ;
#include "F.h"
void f (int i) {
cout << i << endl;
}
#include "F.h"
int main () {
f (10 );
f (10 );
return 0 ;
}
8. nullptr C++中 NULL可能被定义为字面常量 0,C语言中为 (void*)。
nullptr是特殊关键字,它可以隐式转换成其他类型的指针,不能被转换成整数类型。
#include <iostream>
using namespace std;
void f (int x) {
cout << "f(int x)" << endl;
}
void f (int * ptr) {
cout << "f(int* ptr)" << endl;
}
int main () {
f (0 );
f (NULL );
f ((int *)NULL );
f (nullptr );
void * p1 = nullptr ;
int * p2 = p1;
return 0 ;
}