打开效率的大门—C++的基础知识
第一章— C++的基础知识
前言
C语言作为基础语言,带我们走进了编程世界,而今天我们将遇见一座蜿蜒挺拔的大山:C++
本系列运用的是C++ 11 及以上的知识,主要为11版
一、认识C++
C++的定义
C++是一种静态类型、编译式、通用的高级编程语言,由Bjarne Stroustrup于1979年在AT&T贝尔实验室开发。C++是C语言的扩展,支持过程化编程、面向对象编程和泛型编程。
C++的特点
-
高性能:直接操作内存,运行效率接近硬件层面
-
面向对象:支持类、封装、继承和多态,提升代码可维护性
-
泛型编程:通过模板实现通用数据结构,增强代码复用性
-
跨平台兼容:代码可编译为Windows、Linux、macOS等多个系统的可执行文件
-
与C语言兼容:作为C的超集,可直接使用C语言的库和语法
二、C++的基础知识
1.命名空间
对于C语言的命名重复是否感到厌烦?C++的namespace恰好能够解决你的问题。
定义:C++命名空间是一种解决命名冲突的重要机制,通过将全局作用域划分为不同区域来组织代码
- 创建
使用namespace关键字
namespace SXR
{
int num = 10;
}
int main()
{
int num = 5;
std::cout << num << std::endl;
std::cout << SXR::num << std::endl;
}
运行结果为:5 10
同时也可以命名的嵌套
namespace SXR
{
namespace num1
{
int num = 20;
}
namespace num2
{
int num = 30;
}
}
int main()
{
int num = 5;
std::cout << num << std::endl;
std::cout << SXR::num1::num << std::endl;
std::cout << SXR::num2::num << std::endl;
}
运行结果为:5 20 30
当然命名空间中还可以包含函数和结构体等。
- 使用
分为局部与全局使用
全局:using namespace std(通常练习中使用)
局部:std::
2.IO流 input\output stream(初步认识)
-
定义: C++ IO 流是基于流对象实现的输入输出机制,分为标准 IO(控制台)、文件 IO(磁盘文件)、字符串 IO(内存字符串)三大类,本质是数据在 “源 / 目标” 与程序间的字节流传输。(该处主要与标准IO有关)
-
包含函数:
1.cin: 即为char input,是IO流中的输入函数。实现数据的输入,既可以单个赋值,也可多个同时赋值。(可以自动识别类型)
2.cout: 即为char output,是IO流中的输出函数。实现数据的输出,既可以单个输出,也可以多个同时输出。(可以自动识别类型)
3.endl:即为end line,是IO流中实现换行的函数(机制复杂后面章节解释),相当于\n。
//cin函数
int num_1;
float num_2;
double num_3;
std::cin >> num_1;
std::cin >> num_2 >> num_3;
//cout函数
std::cout << SXR::num1::num << '\n' << num << ' ';
std::cout << SXR::num2::num << std::endl;
在竞赛中可能会需要提高输入输出的效率,那么就可以用这个代码
C++中提高IO流效率方法:
std::ios_base::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
3.缺省函数
- 定义: C++ 中的缺省函数(也叫 “默认参数函数”)是指在声明 / 定义函数时,为参数指定默认值,调用函数时若未传递该参数,则自动使用默认值。
- 类别: 根据参数的完全度分为全缺省与半缺省。全缺省即函数参数全赋值,半缺省则为函数参数部分赋值(关键:必须从左到右连续缺省)
//全缺省
void Fun(int a = 0,int b = 5)
{
cout << a << " ";
cout << b<< endl;
}
Fun(10,20);
Fun(5);
Fun();
//半缺省
void Sad(int a, int b = 10)
{
cout << a << " " << b << endl;
}
Sad(4);
Sad(6, 8);
运行结果为:10 20 ;5 20;0 5 ; 4 10 ; 6 8
注意: 声明与定义分离时,只需要声明处给出默认值,否则编译错误
4.重载函数
- 定义: 重载函数是C++中的核心特性,属于多态的一种(编译时多态 / 静态多态),指:在同一作用域内,定义多个同名函数,但参数列表(参数个数、类型、顺序)不同,编译器会根据调用时传入的实参匹配对应的函数。
- 形成关键: 1. 参数个数,2. 参数类型 ,3.参数顺序 (无关 1.返回值类型 2.参数名不同 3.const修饰)
//参数个数
void f()
{
cout << "f()" << endl;
}
void f(int a)
{
cout << "f(int a)" << endl;
}
//参数类型
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(int a, char b)
{
cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
cout << "f(char b, int a)" << endl;
}
Add(10, 20);
Add(10.1, 20.2);
f();
f(10);
f(10, 'a');
f('a', 10);
注意:在构成重载函数时,缺省函数调用会编译报错
void f()
{
cout << abc << endl;
}
void f(int a = 10)
{
cout << a << endl;
}
此处会因为 f() 既可以指向上面的函数,又可以指向下面的缺省函数,编译报错。
5.引用(本节重点)
- 定义: 引用是 C++ 特有的语法特性,本质是变量的 “别名”(Alias) —— 它并非新开辟内存空间,而是对已有变量的内存地址做 “绑定”,操作引用等价于直接操作被绑定的原变量。
类型& 引⽤别名=引⽤对象;
int num;
int& a = num;
甚至可以给一个变量起多个别名,并且变量与别名的地址一致,修改其中一个值,全部都会改变。
int num = 10;
int& a = num;
int& b = a;
cout << num << " " << a << " " << b <<endl;
a = 15;
cout << num << " " << a << " " << b << endl;
-
特性:
- 定义时必须初始化
- 一个变量可以有多个引用
- 引用一旦引用一个实体,就不能引用其他实体
-
使用:
主要用于引用传参和引用做返回值
这里为引用传参
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;
}
可以看到这里实现了通过Swap函数交换下x,y的值。
这里为引用做返回值
int& STTop(ST& rs)
{
assert(rs.top > 0);
return rs.a[rs.top];
}
int main()
{
// 调⽤全局的
ST st1;
STInit(st1);
STPush(st1, 1);
STPush(st1, 2);
cout << STTop(st1) << endl;
STTop(st1) += 10;
cout << STTop(st1) << endl;
return 0;
}
返回的是变量的别名,在main中接受后,可以直接对其存储的数据进行修改
而在C语言中必须返回的是地址,不然只是修改副本而不能对数据本身进行处理
int* STTop(ST* rs)
{
assert(rs->top > 0);
return &rs->a[rs->top];
}
*STTop(&st1) += 10;
这样看来C++的引用确实有助于提高效率
- const引用:
const 引用(const 类型&)是 C++ 中引用的重要变种,核心作用是禁止通过引用修改绑定的变量 / 值,同时支持绑定常量、临时值等只读场景,是 C++ 中保证数据只读、提升代码安全性和灵活性的关键语法。
在此知识点中必须提前了解两个知识点——读写权限和临时对象:-
读写权限
在C++中,const是经典的只读关键字,本质是”通过该标识符不能改变值“,通过const使得数据分为了两种权限——可读可写与只读,而读写权限的核心规则:可收缩,不可扩张,就有了权限的收缩与扩张。 -
临时对象
C++中有这一种由编译器自动创建的未命名对象:临时对象,它通常用来暂存表达式的求值结果,临时对象具有常性,即是右值,因此只能由const修饰的左值引用。
它的生命周期极短,默认在创建它完整表达式结束时销毁,而const能够延长它的生命周期(到main函数结束)。(完整表达式就是分号前的语句)
产生场景:表达式计算;类型隐式转换;函数返回值;匿名对象构造
易错示例:1. 类型隐式转换
-
int main() {
double b = 3.14;
const int& ref = b; // 类型不匹配,发生整型转换,编译器创建临时int对象(值为3)
cout << ref << endl; // 输出3
b = 5.67; // 修改原double变量
cout << ref << endl; // 仍输出3(ref绑定的是临时对象,而非b)
return 0;
}
2. 函数返回值
string getStr()
{
return "hello"; // 返回临时string对象
}
int main() {
// 场景1:值接收 → 临时对象赋值后销毁(C++17后优化为“返回值优化RVO”,可能跳过临时对象)
string s1 = getStr();
// 场景2:const引用接收 → 延长临时对象生命周期
const string& s2 = getStr();
cout << s2 << endl; // 输出hello(临时对象未销毁)
return 0;
}
场景2的本质为const延长了临时变量的生命周期,使得引用&能够锁定getStr函数返回的临时对象。
虽然前提知识复杂庞大,但是在接下来const讲解会很有用。 **^ _ ^**
1. const与引用
int main()
{
const int a = 10;
int& ra = a; 错误
// 编译报错:error C2440: “初始化”: ⽆法从“const int”转换为“int &”
// 这⾥的引⽤是对a访问权限的放⼤
// 这样才可以
const int& ra = a; 正确
//ra++; 错误
// 编译报错:error C3892: “ra”: 不能给常量赋值
int b = 20;
const int& rb = b;
// 这⾥的引⽤是对b访问权限的缩⼩
// rb++;
// 编译报错:error C3892: “rb”: 不能给常量赋值
return 0;
}
第一例:读写权限放大,编译错误
第二例:ra仅为只读权限,不能进行修改
第三例:rb为只读权限,引用对象b为读写,权限收缩正确
并且const有着核心优势,const 加引用可以绑定变量
int main() {
// 1. 绑定常量
const int& ref1 = 5;
cout << ref1 << endl; // 输出5
// 2. 绑定表达式临时值
int a = 1, b = 2;
const int& ref2 = a + b;
cout << ref2 << endl; // 输出3
// 3. 绑定函数返回的临时对象
string getStr() { return "hello"; }
const string& ref3 = getStr();
cout << ref3 << endl; // 输出hello(临时对象生命周期被延长)
// 以下均报错:非const引用无法绑定临时值
// int& ref4 = 5;
// int& ref5 = a + b;
return 0;
}
这里来分析函数参数在:
const 类型&、类型&、 类型的区别与优势
首先,const引用类型可以支持函数参数为常量与表达式
其次,const引用类型为只读权限,而后两种能够改变值,但引用改变的是传入的值,最后一种改变的是副本的值。
区分:可见指针与引用是相似的,但两则其实有着本质区别。
• 语法概念上引⽤是⼀个变量的取别名不开空间,指针是存储⼀个变量地址,要开空间。
• 引⽤在定义时必须初始化,指针建议初始化,但是语法上不是必须的。
• 引⽤在初始化时引⽤⼀个对象后,就不能再引⽤其他对象;⽽指针可以在不断地改变指向对象。
• 引⽤可以直接访问指向对象,指针需要解引⽤才是访问指向对象。
• sizeof中含义不同,引⽤结果为引⽤类型的⼤⼩,但指针始终是地址空间所占个数(32位平台下占4个字节,64位下是8byte)
• 指针很容易出现空指针和野指针的问题,引⽤很少出现,引⽤使⽤起来相对更全⼀些。
6.内联函数
- 定义: 内联函数是 C++ 中用于消除函数调用开销的优化手段,本质是编译器将内联函数的代码 “直接嵌入” 到调用处(而非执行传统的函数调用指令),以空间换时间,提升程序执行效率。(在函数前加上inline)
- 作用: 内联函数可以消除函数调用的开销(如:1. 保存当前函数栈帧 2. 跳转到函数地址执行 3. 执行完毕后返回原地址)
// F.h
#include <iostream>
using namespace std;
inline void f(int i);
// F.cpp
#include "F.h"
void f(int i)
{
cout << i << endl;
}
// main.cpp
#include "F.h"
int main()
{
// 链接错误:⽆法解析的外部符号 "void __cdecl f(int)" (?f@@YAXH@Z)
f(10);
return 0;
}
- 特色: inline是编译器的建议,编译器可以忽略建议,会自行判断是否合适,一般当涉及循环、分支、递归等就会忽略建议
- 注意: 内联函数需要声明与定义在同一处,避免连接错误
w
7. nullptr
使用原因:常规的C/C++中NULL实际是一个宏,在stddef.h文件中可以看到定义
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
可见NULL通常被定义为0或(void*)0,这种情况下会出现:重载函数匹配函数错误和赋值给非指针类型(如int),从而错误。
#include <iostream>
using namespace std;
// 重载函数:一个接收int,一个接收指针
void func(int x) { cout << "调用int版本:" << x << endl; }
void func(char* p) { cout << "调用指针版本" << endl; }
int main() {
func(NULL); // 本意是调用指针版本,但NULL=0,实际调用int版本!
return 0;
}
C++的nullptr则可以解决问题
-
定义: nullptr 是 C++11 引入的一个关键字,用于表示空指针。与传统的 NULL 不同,nullptr 是一个类型安全的空指针常量,能够避免类型不匹配的问题
-
特性:
1.类型:nullptr_t,本质为“指针空值类型”,可转为任意指针类型 2.不可转为非指针类型:无法赋值给非指针类型,编译报错 3.重载匹配:优先匹配指针类型的重载函数 4.可替代使用NULL场景:如 if (p == nullptr) 等价于 if (p == NULL)
总结
C++的新的知识提升了开发效率,实现了更加方便的开发与学习,是学习编程中必不可少的语言学习知识,对以后其他语言的学习将有所帮助。本篇的基础知识讲解完毕
,如有错误和补充,请在评论区发言。谢谢
更多推荐


所有评论(0)