C++ 作为 C 语言的扩展,引入了面向对象和泛型编程。本文重点讲解从 C 迁移到 C++ 的关键概念,包括命名空间解决命名冲突的原理、访问方式及多文件合并机制,以及标准输入输出流 cin/cout 的使用规范。通过对比 C 与 C++ 的 Hello World 实现,深入理解流式 IO 的优势与 endl 缓冲刷新机制,帮助初学者建立正确的 C++ 编程思维。
修罗0 浏览
前言
C++ 是一门高效、灵活且功能强大的通用编程语言,由 Bjarne Stroustrup 于 1979 年在贝尔实验室开发。它通常被视为 C 语言的延伸,在 C 语言的基础上增加了面向对象编程(OOP)和泛型编程的支持。C++ 是一门'难学但上限极高'的语言,如果追求极致的程序运行效率,或者需要深入理解计算机底层运作原理,C++ 是必修课。
我们发现: C 语言和 C++ 虽然同宗同源,但即使是输出简单的 "Hello World",其背后的设计理念也有很大不同。
① C 语言偏向'面向过程',注重直接的函数调用;
② C++ 偏向'面向对象',引入了流(Stream)和命名空间的概念。
所以,想吃透 C++ 的第一个程序,我们需要先掌握必要的前置知识。
二、命名空间
对于初学 C++ 的朋友,肯定会疑惑这句代码是什么意思,在 C 语言中从来没有看见过:
usingnamespace std;
其实,命名空间(Namespace)是 C++ 为了解决 C 语言中'命名冲突'这一痛点而引入的关键特性。因为在 C/C++ 中,变量、函数和类都是大量存在的,这些标识符将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
#include<stdio.h>namespace mount {
int a = 0;
int b = 1;
}
intmain(){
// 编译报错:error C2065: 'a': 未声明的标识符printf("%d\n", a);
return0;
}
如果我们想要使用命名空间中定义的变量/函数,有三种方式:
指定命名空间访问,大型项目中推荐这种方式。
using 将命名空间中某个成员展开,项目中经常访问的不存在冲突的成员推荐这种方式。
展开命名空间中全部成员,项目不推荐,冲突风险很大,日常小练习程序为了方便推荐使用。
:: 为域作用限定符,左边无命名空间名时,默认为全局。
当域作用限定符左边有命名空间名时,在该命名空间中寻找并调用。
当域作用限定符左边没有命名空间名时,默认在全局中寻找并调用。
2.4.1 指定命名空间访问
代码示例:
#include<stdio.h>namespace mount {
int a = 10;
voidf(){ printf("func N\n"); }
intadd(int a, int b){ return a + b; }
structNode {
structNode* next;
int val;
};
}
int c = 10; // 全局变量intmain(){
// 调用命名空间中的变量printf("%d\n", mount::a);
// 调用命名空间中的无参函数
mount::f();
// 调用命名空间中的有参函数
mount::add(1, 2);
// 声明命名空间中的结构体变量structmount::Node n1;
// 调用全局域的变量printf("%d\n", ::c);
return0;
}
2.4.2 展开命名空间中某个成员
#include<stdio.h>namespace mount {
int a = 10;
voidf(){ printf("func N\n"); }
intadd(int a, int b){ return a + b; }
structNode {
structNode* next;
int val;
};
}
using mount::a;
using mount::f;
intmain(){
// 展开后无需使用域限定符进行访问printf("%d", a);
f();
return0;
}
2.4.3 展开命名空间中全部成员
#include<stdio.h>namespace mount {
int a = 10;
voidf(){ printf("func N\n"); }
intadd(int a, int b){ return a + b; }
structNode {
structNode* next;
int val;
};
}
usingnamespace mount;
intmain(){
// 展开命名空间中全体成员后// 所有成员都无需使用域空间名进行访问printf("%d", a);
f();
add(1, 2);
structNode n1;
return0;
}
这样我们也就理解了为什么出现了 using namespace std;。因为 C++ 标准库都放在一个叫 std(standard) 的命名空间中,我们通过将其展开,无需通过加上前缀 std::,就可以便捷地使用。
2.5 namespace 的嵌套定义
命名空间的嵌套就像电脑文件夹里的'子文件夹'。当项目变得非常巨大时,仅仅一层命名空间可能不够用了。比如:一个大型游戏引擎,可能所有的代码都在 Game 命名空间下,但里面又分'图形'、'音频'、'网络'等模块。
namespace Game {
// Game 下的 Graphics 模块namespace Graphics {
voidrender(){ printf("正在渲染画面...\n"); }
}
// Game 下的 Audio 模块namespace Audio {
voidplaySound(){ printf("正在播放声音...\n"); }
}
}