当前位置: 首页 > news >正文

c++-base

C++基础语法

1. namespace命名空间

命名空间是C++中用于划分代码,防止命名冲突的重要机制。它可以将全局作用域划分为不同的命名区域,让相同名称的标识符在不同命名空间中互不干扰。C++中域分为函数局部域、全局域、命名空间域、类域。

1.1 命名空间的定义

命名空间中可以定义变量、函数、类等。

namespace name {int value = 0;void func() {}class Obj {};
}

1.2 命名空间的访问

编译查找一个变量时的声明/定义时,默认只会在局部或者全局查找,不会到命名空间里去查找,所以要访问命名空间中的变量/函数,有三种方式。

1.2.1 域作用限定符

访问命名空间,使用域作用修饰限定符 ::

name::value = 10;
name::func();
name::Obj obj;
1.2.2 using声明引入特定成员
using name::value;
value = 10;
1.2.3 using引入整个命名空间
using namespace name;
value = 10;
func();
Obj obj;

项目中不推荐这种方式。

1.3 全局变量的访问

当局部变量和全局变量冲突时,根据就近原则默认访问的是局部变量,这时我们可以通过::来访问全局变量。

#include <iostrea>
using namespace std;
int a = 100;
int main () {int a = 10;cout << a << endl;    // 10cout << ::a << endl;  // 100
}

1.4 命名空间的特性

1.4.1 命名空间的嵌套
namespace Outer {int x = 10;namespace Inner {int y = 20;}
}// 访问方式
Outer::x;
Outer::Inner::y;
1.4.2 命名空间可以分段定义

多文件中可以定义同名的namespace,他们会默认合并到一起。

// 文件1.cpp
namespace MyNS {void func1();
}// 文件2.cpp
namespace MyNS {void func2();
}
1.4.3 命名空间别名
namespace name {int x = 10;
}
namespace newName = name;    // 别名
newName::x;
name::x;

C++标准库都放在std的命名空间中。

2. C++输入输出

<iostream>是Input Output Stream的缩写,是标准输入、输出流库,定义了标准输入输出对象。

cin、cout可以自动识别类型。

2.1 标准输入

std::cin是istream类的对象,它是标准输入流。

#include <iostream>
int main () {int a = 0;float f = 0;std::cin >> a >> f;
}

>>流提取运算符,本质是运算符重载。

2.2 标准输出

std::cout是ostream类的对象,它是标准输出流。

#include <iostream>
int main () {int a = 10;float f = 22.22;std::cout << a << f;
}

<<流插入运算符,本质是运算符重载。

2.3 提升输入输出效率

ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);

io需求比较高时,添加这三行代码可以提升C++IO效率。

3. 缺省参数

缺省参数是定义或声明函数时为函数参数指定一个缺省值,调用该函数时,若没有传参则使用缺省值,否则使用指定形参。

带缺省参数的函数调用,C++规定必须从左到右依次传参,不能跳跃

3.1 全缺省

全缺省是给所有形参一个缺省值。

void func(int a = 10 , int b = 20 , int c = 30) {}

3.2 半缺省

半缺省是给部分形参缺省值。C++规定半缺省参数必须从右往左依次连续缺省,不能跳跃。

void func(int a , int b = 10, int c = 20) {}

函数定义和声明分离时,缺省参数不能在函数定义和声明中同时出现,C++规定必须在函数声明处给缺省值。

4. 函数重载

C++支持在同一作用域中出现同名函数,但是这些函数的参数列表必须不同。

4.1 函数重载基本规则

  1. 函数名必须相同

  2. 参数列表必须不同

    • 参数类型不同

    • 参数个数不同

    • 参数顺序不同(仅当类型不同时有效)

  3. 返回值不同并不能区分重载

4.2 C++支持函数重载原理

为什么C++支持函数重载,而C不支持呢?以Linux环境为例。

首先函数的声明只是为了编译通过,而具体的实现是编译器在链接阶段去找函数的地址,那么在链接时,假设面对Add函数,链接器会使用什么函数名去找呢?其实每个编译器都有一套自己的函数名修饰规则

函数名修饰规则:编译器在编译时会将函数名和参数信息结合,生成一个全局唯一的内部名称,以此区分函数重载。

C语言中函数名修饰规则:直接使用定义/声明中的函数名,在链接时,编译器会直接使用函数名寻找函数地址。

C++中函数名修饰规则:_Z + 函数名长度 + 函数名 + 类型首字母。

int add(int a, int b){}    // 修饰后的函数名: _Z3addii

上述可以深刻的理解为什么C语言中不支持函数重载?因为函数名修饰规则会导致寻找函数地址时发生冲突;为什么函数重载并不用返回值来区分?因为函数名修饰规则。

5. 引用

引用在语法上是为一个已经存在的变量起别名,可以理解为并不占用空间。

5.1 引用的特性

  • 引用在定义时必须初始化

  • 一个变量可以有多个引用

  • 引用一旦引用一个实体,就不能改变指向了

#include <iostream>
using namespace std; int main () { int x = 0; int& b = x;     // b为x的别名 修改b相当于修改x 使用b相当于使用 int& c = x;     // 一个变量可以有多个引用int num = 10;b = num;        // 引用一旦引用实体,则不能改变指向,这行代码的意思是把num值赋值给b也就是x        return 0;
}

5.2 const引用

const引用既可以引用普通对象,也可以引用一个const对象,但是在C++中,const引用有时候是必不可少的。

5.2.1 const引用权限放大缩小问题

引用的权限可以缩小,但是不能放大。

/**  int a是一个普通变量可以读可以写*  const int& 表示的是该引用类型的别名 只能读不能修改*  相当于对于引用是权限的缩小(√)
*/
int a = 10;
const int& ref1 = a;/**  const int a是一个常量可以读,但是不能写*  int& 表示的是该引用类型的别名,可以读可以修改*  我本身的变量都不能修改,但是却要赋值给一个可以修改引用别名上,这是权限的放大(❌)
*/
const int b = 10;
int& ref2 = b;

注意:只有引用和指针才有权限放大缩小问题。

5.2.2 const引用使用场景
// 1.const引用常量
const int& ref1 = 10;
// 2.const引用const变量
const int num = 10;
const int& ref2 = num;
// 3. const引用函数返回值
int test () {int x = 100;return x; 
}
int& ref3 = test();        // ×
// 返回值x会产生一个临时的对象,把x的值赋值给这个临时的对象,而临时对象具有常性不能修改,所以要使用const引用
const int& ref3 = test();  // √
// 4. const引用表达式
int a = 1;
int b = 2;
const int& ref4 = a + b;    // a+b这个表达式会产生一个临时的对象,而临时对象具有常性不能修改,只能使用const引用
// 5. const引用发生类型转换
float f = 1.1;
const int& ref5 = f;    // float类型赋值给int类型,会产生一个临时的对象,把f变量截断后的整数赋值给临时对象,

产生临时对象/变量的场景:

  1. 函数返回值

  2. 一些表达式(a+b、a*3等)

  3. 类型转换

  • 所谓临时对象/变量就是编译器需要一个空间暂存表达式的结果,临时创建的一个未命名的对象/变量(大部分情况是寄存器),而临时对象/变量是具有常性的不能修改。

  • 临时对象/变量被const引用,会延长其生命周期。

5.3 指针和引用的区别

引用指针
1语法上引用代表变量的别名,不开辟空间指针是存储一个变量的地址,需要开辟空间
2引用定义时必须初始化指针定义时可以不初始化
3引用不可以改变指向指针可以改变指向
4引用可以直接访问对象指针需要解引用才能访问对象
5sizeof(引用)表示是被引用对象的大小sizeof(指针)表示指针的大小(32位机器4字节、64位机器8字节)
6引用相较于指针更安全一些指针会出现野指针等情况

6. inline

使用inline关键字修饰的函数称为内联函数,编译时C++编译器会在调用的地方展开内联函数,而无需建立栈帧提高效率,内联函数的出现主要是替代宏函数。

宏函数有许多坑,比如写一个Add宏函数。

#define Add(x , y) ((x)+(y))
  • 为什么不能加分号?因为宏函数可能在if语句或输出语句中调用,带分号会编译报错

  • 为什么要加外面的括号?因为有运算符优先级问题,比如Add(1 , 2) * 5没有外层括号会产生意想不到的结果

  • 为什么要加里面的括号?因为有运算符优先级问题,比如Add(1 | 2 , 3 ^ 5)没有内层括号会产生意想不到的结果

inline的特性:

  • inline是一个建议性的选项,inline适合短小的函数,对于代码量大的函数或递归函数,编译器会忽略。

  • debug版本下面默认不展开inline函数,这样方便调试。

  • inline函数不能声明和定义分离,会导致链接错误。 因为inline函数默认是展开,没有函数地址,调用时也就找不到具体实现,无法完成展开。建议inline函数直接写在.h文件中。

7. nullptr

nullptr是C++11中引入的关键字,用于表示空指针常量。它解决了传统NULL宏在C++中一些问题,提供了更安全、更明确的空指针表示方式。

在C++中NULL通常被定义0,在C语言中NULL通常被定义为((void*)0),但是无论哪种方式,都会导致一些问题。

void test(int);
void test(char*);test(NULL);    // 调用哪个?调用的是test(int),而不是预期的test(char*)

C++中推荐使用nullptr。

http://www.dtcms.com/a/276651.html

相关文章:

  • ActionPeice-ICML2025-谷歌deepmind-生成式推荐中上下文感知分词技术
  • 深入浅出:RS232、RS485、UART、Modbus与差分信号、共模信号的那些事儿
  • 力扣刷题(第八十五天)
  • dubbo源码学习3-dubbo反射调用服务源码分析
  • Unity开发中常用的洗牌算法
  • 数据结构——散列表
  • 数据结构栈的实现(C语言)
  • C语言--原码、反码、补码转换
  • 知识宇宙-思考篇:AI大模型如何重塑软件开发流程?
  • Sentinel+nacos实现push模式规则持久化
  • Java生产带文字、带边框的二维码
  • matplotlib:饼图、环形图、爆炸式饼图
  • 五、深度学习——CNN
  • Raft 代码分析
  • 基于STM32F412+RT-Thread的智能汽车CAN通信仪表盘
  • 深度学习-卷积化
  • Kerberos5 安装
  • 2025XYD Summer Camp 7.11 模考
  • scrapy项目开发流程
  • jQuery 头像裁剪实现
  • 若依前后端分离Vue3版本接入阿里云OSS
  • GoC之汉诺塔绘制
  • JavaSE重点知识
  • 【文献阅读】DEPTH PRO: SHARP MONOCULAR METRIC DEPTH IN LESS THAN A SECOND
  • 【王树森推荐系统】行为序列02:DIN模型(注意力机制)
  • 第10讲——一元函数积分学的几何应用
  • 第八讲~~数据库技术
  • 【InnoDB内存结构】缓冲池,变更缓冲区,自适应哈希索引,日志缓冲区
  • 【项目】GraphRAG基于知识图谱的检索增强技术-实战入门
  • 代码随想录算法训练营65期第17天