C++ 是一种通用的、高效的编程语言,广泛应用于系统编程、游戏开发、嵌入式系统、高性能计算等领域。
它是 C 语言 的扩展,同时支持面向过程编程和面向对象编程(OOP)。事实上,任何合法的 C 程序都是合法的 C++ 程序。
C++ 由 Bjarne Stroustrup 于 1980 年代初期在贝尔实验室开发,最初被称为“C with Classes”。
注意:使用静态类型的编程语言是在编译时执行类型检查,而不是在运行时执行类型检查。
template
)支持泛型编程,提高代码复用性。标准的 C++ 由三个重要部分组成:
C++ 标准不断更新,主要版本包括:
C++ 编译器 是将 C++ 源代码转换为机器代码的工具,使程序能够在计算机上运行。
GCC(GNU Compiler Collection):GCC是一个开源的编译器套件,包括C++编译器(g++)。它是许多Linux发行版的默认编译器,也可在其他操作系统上使用。
特点:开源、跨平台(支持 Linux、Windows、macOS 等)。支持最新的 C++ 标准(如 C++20)。性能优秀,广泛应用于开源项目。
简介:Clang 是 LLVM 项目的一部分,专注于提供快速编译和清晰的错误信息。
特点: 开源、跨平台。编译速度快,错误信息友好。支持最新的 C++ 标准。
IDE 集成了编译器、编辑器、调试器等工具,提供更便捷的开发体验。以下是常用的 C++ IDE:
如果你不想安装本地编译器,可以使用在线编译器快速测试代码:
Wandbox:https://wandbox.org/
OnlineGDB【体验好,有代码自动补充】:https://www.onlinegdb.com/
让我们看一段简单的代码,可以输出单词 Hello World。
#include <iostream>
using namespace std;
// main() 是程序开始执行的地方 是一个单行注释。
int main() {
cout << "Hello world" << endl;
return 0;
}
通常我们使用 -o 选项指定可执行程序的文件名,以下实例生成一个 hello 的可执行文件:
$ g++ main.cpp -o hello
$ ./hello
hello world
C++ 语言定义了一些头文件,这些头文件包含了程序中必需的或有用的信息。上面这段程序中,包含了头文件 <iostream>。
下一行 using namespace std; 告诉编译器使用 std 命名空间。命名空间是 C++ 中一个相对新的概念。
下一行 // main() 是程序开始执行的地方 是一个单行注释。单行注释以 // 开头,在行末结束。
下一行 int main() 是主函数,程序从这里开始执行。
下一行 cout << "Hello World"; 会在屏幕上显示消息 "Hello World"。
下一行 return 0; 终止 main( )函数,并向调用进程返回值 0。
最简单的编译方式:
$ g++ main.cpp
由于命令行中未指定可执行程序的文件名,编译器采用默认的 a.out。程序可以这样来运行:
$ ./a.out
hello world
g++ program.cpp -o program
#如果是这样,那么默认会生成a.out
g++ program.cpp
g++
:调用 GCC 编译器。program.cpp
:源代码文件。-o program
:指定输出文件名为 program
。g++ main.cpp utils.cpp -o program
g++ Account.cpp Bank.cpp FileManager.cpp BankUserManager.cpp -o BankUserManager
g++ 有些系统默认是使用 C++98,我们可以指定使用 C++11 来编译 main.cpp 文件:
g++ -g -Wall -std=c++11 main.cpp
g++ -std=c++11 -o program program.cpp
-std=c++11
:指定使用 C++11 标准。
g++ -O2 -o program program.cpp
g++ -O2
中的 -O2
表示启用编译器的优化级别 2。这是 GCC/G++ 编译器提供的一组预定义的优化策略,旨在提高生成代码的执行效率。以下是详细解释:
-O2 包含的主要优化技术:
优化技术 | 说明 |
---|---|
指令调度 | 重新排列指令以充分利用CPU流水线 |
循环优化 | 简化循环结构,减少分支开销 |
死代码消除 | 删除永远不会执行的代码 |
常量传播 | 用已知常量值替换变量 |
函数内联 | 将小函数直接插入调用位置(有限度) |
尾调用优化 | 重用栈帧进行递归调用 |
-O0
或 -Og
(优化调试体验)-O2
-O2
(稳定性和性能的平衡)-O3
,但需测试稳定性# 调试版本(无优化)
g++ -g -o program program.cpp
# 发布版本(推荐优化)
g++ -O2 -o program program.cpp
# 激进优化版本(可能风险)
g++ -O3 -o program program.cpp
注意:优化级别越高,编译时间越长,且可能增加调试难度(变量可能被优化掉)。
-O2
在大多数情况下是最佳选择,能在性能提升和稳定性之间取得良好平衡。
g++ -g -o program program.cpp
在编译程序时,使用 -g选项会生成调试信息。这些信息允许调试器(如 GDB)将机器代码与源代码关联起来,从而进行源代码级别的调试。
调试信息是什么?调试信息是嵌入在可执行文件中的额外数据,它建立了机器代码与源代码之间的映射关系,使调试器能够:
调试信息包含的关键内容
信息类型 | 作用 | 示例 |
---|---|---|
行号信息 | 将机器指令映射到源代码行 |
|
符号表 | 函数/变量名到内存地址的映射 |
|
类型信息 | 变量类型和结构体定义 |
|
作用域信息 | 变量可见范围 |
|
宏定义 | 预处理器宏的原始定义 |
|
调试信息如何工作
+-------------------+ +-------------------+ +-------------------+
| 源代码 (C++) | | 带调试信息的可执行文件 | | 调试器 |
| | | | | (GDB, LLDB, IDE) |
| int main() { | | 机器指令 + | | |
| int a = 5; |---->| 调试信息表 |---->| 显示变量值 |
| return a; | | (行号、符号、类型) | | 设置断点 |
| } | | | | 单步执行 |
+-------------------+ +-------------------+ +-------------------+
在 C++ 中,注释 是用于解释代码的文本,编译器会忽略注释内容。注释对于提高代码的可读性和维护性非常重要,尤其是在团队协作或长期维护的项目中。
提示:编译器在编译代码时,会忽略注释的内容
单行注释:// 描述信息
通常放在一行代码的上方,或者一条语句的末尾,==对该行代码说明==
int main() {
// 输出 Hello, World!
cout << "Hello, World!" << endl; // 这是行尾注释
return 0;
}
多行注释: /* 描述信息 */
通常放在一段代码的上方,==对该段代码做整体说明==
/*
这是一个简单的 C++ 程序
用于输出 Hello, World!
*/
int main() {
cout << "Hello, World!" << endl;
return 0;
}
C++ 支持使用文档注释生成 API 文档,常用的工具包括:
命名空间(Namespace) 是 C++ 中用于组织代码的机制,它可以避免命名冲突,尤其是在大型项目或使用第三方库时。命名空间将代码逻辑分组,并为其中的标识符(如变量、函数、类等)提供作用域。
遇到问题:一个中大型软件往往由多名程序员共同开发,会使用大量的变量和函数,不可避免地会出现变量或函数的命名冲突。当所有人的代码都测试通过,没有问题时,将它们结合到一起就有可能会出现命名冲突。
场景例如:您可能会写一个名为 xyz() 的函数,在另一个可用的库中也存在一个相同的函数 xyz()。这样,编译器就无法判断您所使用的是哪一个 xyz() 函数。
解决办法:因此,引入了命名空间这个概念,可作为附加信息来区分不同库中相同名称的函数、类、变量等。使用了命名空间即定义了上下文。本质上,命名空间就是定义了一个范围。
作用:防止命名冲突,将代码逻辑分组。语法:
namespace 命名空间名 {
// 变量、函数、类等
}
访问方式:
命名空间名::标识符
访问命名空间中的成员。using namespace 命名空间名;
引入整个命名空间。using 命名空间名::标识符;
引入特定成员。namespace MyNamespace {
int value = 42; // 变量
void print() { // 函数
cout << "Hello from MyNamespace!" << endl;
}
}
#include <iostream>
using namespace std;
int main() {
cout << MyNamespace::value << endl; // 访问变量
MyNamespace::print(); // 调用函数
return 0;
}
使用 using namespace
可以引用整个空间
#include <iostream>
using namespace std;
namespace MyNamespace {
int value = 42;
void print() {
cout << "Hello from MyNamespace!" << endl;
}
}
using namespace MyNamespace; // 引入整个命名空间
int main() {
cout << value << endl; // 直接访问变量
print(); // 直接调用函数
return 0;
}
使用 using
引入特定成员
#include <iostream>
using namespace std;
namespace MyNamespace {
int value = 42;
void print() {
cout << "Hello from MyNamespace!" << endl;
}
}
using MyNamespace::value; // 引入特定成员
int main() {
cout << value << endl; // 直接访问变量
MyNamespace::print(); // 仍需使用命名空间访问函数
return 0;
}
命名空间可以嵌套,形成层次结构。示例
namespace Outer {
namespace Inner {
void print() {
cout << "Hello from Inner namespace!" << endl;
}
}
}
int main() {
Outer::Inner::print(); // 访问嵌套命名空间
return 0;
}
匿名命名空间用于定义仅在当前文件内可见的成员,类似于 static
关键字。示例
namespace {
int value = 42; // 仅在当前文件内可见
}
int main() {
cout << value << endl; // 直接访问
return 0;
}
可以为命名空间定义别名,简化代码。示例
namespace VeryLongNamespaceName {
void print() {
cout << "Hello!" << endl;
}
}
namespace VLN = VeryLongNamespaceName; // 定义别名
int main() {
VLN::print(); // 使用别名访问
return 0;
}
C++ 标准库的所有内容都定义在 std
命名空间中。
示例
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl; // 使用 std:: 访问
return 0;
}
引入 std
命名空间
#include <iostream>
using namespace std; // 引入 std 命名空间
int main() {
cout << "Hello, World!" << endl; // 直接访问
return 0;
}
namespace space名称
可以定义命名空间。通过命名空间可以调用所在区域函数using namespace space名称
可以通过该方式引入命名空间。这个指令会告诉编译器,后续的代码将使用指定的命名空间中的名称。//定义命名空间
namespace first_space {
void fun() {
cout << "Inside first_space" << endl;
}
}
namespace second_space {
void fun() {
cout << "Inside second_space" << endl;
}
}
void test1() {
cout << "定义命名空间" << endl;
// 调用第一个命名空间中的函数
first_space::fun();
// 调用第二个命名空间中的函数
second_space::fun();
}
//using 指令
using namespace first_space;
//using 指令引入的名称遵循正常的范围规则。名称从使用 using 指令开始是可见的,直到该范围结束。此时,在范围以外定义的同名实体是隐藏的。
void test2() {
cout << "using 指令" << endl;
fun();
}
//嵌套的命名空间
namespace first_sp{
void funSp() {
cout << "Inside first_sp,逗比充1" << endl;
}
namespace second_sp {
void funSp() {
cout << "Inside second_sp,逗比充2" << endl;
}
}
}
using namespace first_sp::second_sp;
void test3() {
cout << "嵌套的命名空间" << endl;
// 调用第二个命名空间中的函数
funSp();
}
int main() {
test1();
test2();
test3();
return 0;
}
在 C++ 中,头文件是用于声明类、函数、变量等的文件,通常以 .h
或 .hpp
为扩展名。
.h
:传统的 C 和 C++ 头文件扩展名,广泛使用。.hpp
:更现代的 C++ 头文件扩展名,通常用于强调该头文件是专门为 C++ 设计的。.hh
:在某些项目中也会使用,通常是 UNIX 或 Linux 社区的风格。.tpp
:用于模板类或函数的实现文件(通常与 .hpp
配合使用)。扩展名 | 语言 | 用途 | 适用场景 |
---|---|---|---|
| C 和 C++ | 传统头文件,兼容 C 和 C++ | 兼容 C 和 C++ 的项目 |
| C++ | 现代 C++ 头文件,强调 C++ 特性 | 纯 C++ 项目 |
| C++ | 特定社区风格的头文件 | UNIX 或 Linux 社区的项目 |
| C++ | 模板类或模板函数的实现文件 | 需要分离模板声明与实现的项目 |
头文件中只放类、函数、变量的声明,具体实现放在 .cpp
文件中。建议每个类单独一个头文件,便于维护和管理。 例如:
头文件声明:
// MyClass.h
class MyClass {
public:
void doSomething();
};
实现类做具体实现:
// MyClass.cpp
#include "MyClass.h"
void MyClass::doSomething() {
// 实现
}
使用头文件保护(#ifndef
/ #define
或 #pragma once
)防止重复包含。 例如:
// MyClass.h
#ifndef MYCLASS_H
#define MYCLASS_H
class MyClass {
public:
void doSomething();
};
#endif // MYCLASS_H
在 C++ 中,修饰符和标志符是用于修饰变量、函数、类等的关键字或符号,它们可以改变对象的属性、行为或作用域。
访问控制修饰符用于定义类成员的访问权限。
public
:公有成员,任何地方都可以访问。protected
:受保护成员,只有类本身、派生类可以访问。private
:私有成员,只有类本身可以访问。存储类型修饰符用于定义变量的存储方式和生命周期。
auto
:自动变量,编译器自动推导类型(C++11 引入)。register
:建议将变量存储在寄存器中(现代编译器通常忽略)。static
:静态变量,生命周期贯穿整个程序。extern
:声明变量在其他文件中定义。mutable
:允许在 const
对象中修改成员变量。类型限定符用于修饰变量的行为或属性。
const
:表示变量不可修改。volatile
:表示变量可能被外部修改,禁止编译器优化。restrict
:用于指针,表示指针是唯一访问内存的方式(C99 引入,C++ 中不常用)。示例:
const int a = 10; // 常量
volatile int b = 20; // 易变变量
函数修饰符用于限定函数的行为。
inline
:建议编译器将函数内联。virtual
:表示函数是虚函数,可以被派生类重写。override
:明确表示重写基类的虚函数(C++11 引入)。final
:禁止派生类重写虚函数(C++11 引入)。constexpr
:表示函数可以在编译时求值(C++11 引入)。示例:
class Base {
public:
virtual void func() const; // 虚函数
};
class Derived : public Base {
public:
void func() const override; // 重写基类虚函数
};
类修饰符用于限定类的行为。
final
:禁止类被继承(C++11 引入)。abstract
:通过纯虚函数实现抽象类(没有直接的关键字,纯虚函数实现)。示例:
class Base final { // 禁止继承
// 类定义
};
friend
:允许非成员函数或其他类访问私有成员。explicit
:禁止构造函数的隐式转换(C++11 引入)。noexcept
:表示函数不会抛出异常(C++11 引入)。示例:
class MyClass {
friend void friendFunc(); // 友元函数
};
作用:C++规定给标识符(变量、常量)命名时,有一套自己的规则
C++ 标识符是用来标识变量、函数、类、模块,或任何其他用户自定义项目的名称。
建议:给标识符命名时,争取做到见名知意的效果,方便自己和他人的阅读
有效标志符,一个标识符以字母 A-Z 或 a-z 或下划线 _ 开始,后跟零个或多个字母、下划线和数字(0-9)。
无效标志符,C++ 标识符内不允许出现标点字符,比如 @、& 和 %。C++ 是区分大小写的编程语言。
C++ 中的关键字是语言保留的标识符,具有特定的含义和用途,不能用作变量名、函数名或其他用户定义的标识符。
C++ 的关键字包括从 C 继承的关键字以及 C++ 自己引入的关键字。
作用:关键字是C++中预先保留的单词(标识符)
C++关键字如下:
asm | do | if | return | typedef |
---|---|---|---|---|
auto | double | inline | short | typeid |
bool | dynamic_cast | int | signed | typename |
break | else | long | sizeof | union |
case | enum | mutable | static | unsigned |
catch | explicit | namespace | static_cast | using |
char | export | new | struct | virtual |
class | extern | operator | switch | void |
const | false | private | template | volatile |
const_cast | float | protected | this | wchar_t |
continue | for | public | throw | while |
default | friend | register | true | |
delete | goto | reinterpret_cast | try |
提示:在给变量或者常量起名称时候,不要用C++得关键字,否则会产生歧义。
这些关键字用于定义变量或函数的类型。
关键字 | 含义 |
---|---|
| 整型 |
| 浮点型 |
| 双精度浮点型 |
| 字符型 |
| 布尔型( |
| 无类型 |
| 宽字符型 |
| 长整型 |
| 短整型 |
| 有符号类型 |
| 无符号类型 |
这些关键字用于定义变量的存储方式和生命周期。
关键字 | 含义 |
---|---|
| 自动类型推导(C++11 引入) |
| 静态变量 |
| 外部变量 |
| 寄存器变量(建议存储在寄存器中,现代编译器通常忽略) |
| 允许在 |
这些关键字用于控制程序的执行流程。
关键字 | 含义 |
---|---|
| 条件语句 |
| 条件语句的分支 |
| 多分支选择语句 |
|
|
|
|
| 循环语句 |
| 循环语句 |
| 循环语句 |
| 跳出循环或 |
| 跳过本次循环 |
| 从函数返回 |
| 无条件跳转 |
这些关键字用于定义和操作类、对象和继承。
关键字 | 含义 |
---|---|
| 定义类 |
| 定义结构体 |
| 定义联合体 |
| 定义枚举 |
| 私有访问权限 |
| 受保护访问权限 |
| 公有访问权限 |
| 虚函数 |
| 重写基类虚函数(C++11 引入) |
| 禁止继承或重写(C++11 引入) |
| 禁止隐式转换(C++11 引入) |
| 友元函数或友元类 |
| 当前对象的指针 |
| 动态分配内存 |
| 释放动态分配的内存 |
这些关键字用于处理异常。
关键字 | 含义 |
---|---|
| 尝试执行一段代码 |
| 捕获异常 |
| 抛出异常 |
| 表示函数不会抛出异常(C++11 引入) |
这些关键字用于进行显式类型转换。
关键字 | 含义 |
---|---|
| 静态类型转换 |
| 动态类型转换 |
| 去掉或添加 |
| 重新解释类型 |
这些关键字用于定义或重载操作符。
关键字 | 含义 |
---|---|
| 重载操作符 |
| 获取对象或类型的大小 |
| 获取对象的类型信息 |
| 获取类型的对齐要求(C++11 引入) |
这些关键字用于定义和操作模板。
关键字 | 含义 |
---|---|
| 定义模板 |
| 定义模板参数或别名 |
| 编译时常量(C++11 引入) |
| 推导表达式的类型(C++11 引入) |
这些关键字用于定义和操作命名空间。
关键字 | 含义 |
---|---|
| 定义命名空间 |
| 使用命名空间或类型别名 |
这些关键字用于其他特殊用途。
关键字 | 含义 |
---|---|
| 空指针(C++11 引入) |
| 静态断言(C++11 引入) |
| 模块导出(C++20 引入) |
| 模块导入(C++20 引入) |
| 定义概念(C++20 引入) |
| 协程等待(C++20 引入) |
| 协程生成值(C++20 引入) |
| 协程返回值(C++20 引入) |
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。