【C++】入门(一)

在这里插入图片描述

前言:
本篇博客将带大家认识C++,熟悉基本语法


文章目录

  • 认识C++
    • C++的诞生与发展
    • C++ 在行业中的运用
  • 一、命名空间
    • 1.1 命名空间的定义
    • 1.2 命名空间的使用
    • 1.3 命名空间的访问
  • 二、C++输入&输出
    • 输出操作符 `<<`
    • 输入操作符 `>>`
    • 换行符和刷新输出缓冲区
    • 关键字 using
  • 三、缺省参数
    • 3.1 概念
    • 3.2 缺省参数分类
  • 四、函数重载
    • 概念
    • 函数重载的原理

认识C++

C++的诞生与发展

C++ 是由丹麦计算机科学家贝尔纳斯·斯特劳斯特博士(Bjarne Stroustrup)于20世纪80年代初期开发的。他在贝尔实验室工作时,对 C 语言进行了扩展,加入了OOP(object oriented programming:面向对象)思想,从而诞生了 C++。C++ 的名字中的 “++” 表示在 C 语言的基础上的一个增量,暗示这是对 C 的增强和扩展。因此:它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计。

C++ 在其发展过程中经历了多个标准版本的发布,其中最早的标准是于1998年发布的 C++98,之后又有 C++03、C++11、C++14、C++17 和 C++20 等版本。每个版本都引入了新的特性和改进,使得 C++ 成为一个强大而灵活的编程语言。

" C with Classes" 是 C++ 的前身,这个术语最初用于描述贝尔纳斯·斯特劳斯特博士在开发 C++ 时的初期版本。C++ 最初是在 C 语言的基础上引入了一些面向对象编程的概念,而 “C with Classes” 就是这个过渡阶段的命名。

C++ 在行业中的运用

  1. 系统级编程: C++ 被广泛用于开发操作系统、驱动程序和其他系统级软件,因为它提供了对硬件的底层访问和高效的系统编程能力。

  2. 游戏开发: 许多游戏引擎和大型游戏项目都使用 C++。其高性能和底层控制使其成为游戏行业的首选语言之一。

  3. 嵌入式系统: C++ 被用于开发嵌入式系统,如智能家居设备、汽车控制系统等。它的效率和灵活性使其适用于资源受限的环境。

  4. 金融领域: 在金融行业,C++ 被广泛用于开发高性能的交易系统、风险管理工具和其他金融应用。

  5. 图形界面应用: C++ 被用于开发桌面应用程序、图形用户界面(GUI)和各种图形软件。

  6. 网络编程: C++ 的网络库和框架使其成为开发网络应用和服务器端程序的理想选择。

C++ 以其高性能、灵活性和底层控制能力,成为许多领域中首选的编程语言之一。


一、命名空间

命名空间(Namespace)是一种在C++中用于组织和封装代码的机制。它允许将一组相关的标识符(如变量、函数、类等)封装在一个逻辑单元中,目的是对标识符的名称进行本地化,以避免命名冲突或名字污染。命名空间可以被定义在全局作用域或其他命名空间内。

1.1 命名空间的定义

语法:

namespace 名称 {// 命名空间内的代码块// 变量、函数、类的声明和定义等
}
  1. 命名空间中可以定义变量/函数/类型

    namespace Namespace {// 变量int rand = 10;//函数int Add(int left, int right) {return left + right;}//类型struct Node {struct Node* next;int val;};
    }
    
  2. 命名空间可以嵌套

    // 外层命名空间
    namespace N1{int a;int Add(int left, int right){return left + right;}// 内层命名空间namespace N2{int c;int Sub(int left, int right){return left - right;}}
    }
    
  3. C++ 允许命名空间的逐渐定义,而多个定义会在编译时进行合并,确保同一命名空间内的内容是唯一的。
    在这个例子中,num3 命名空间的两个部分分别定义在不同的文件中,但它们最终会在编译时合并成为一个包含两个成员的命名空间。

    // 文件1.cpp
    namespace num3 {int rand = 3;
    }// 文件2.cpp
    namespace num3 {int y = 4;
    }
    

1.2 命名空间的使用

以下是一些常见的命名空间的使用场景和实践:

  1. 避免全局命名冲突: 命名空间允许将相关的标识符封装在一个独立的逻辑单元中,从而避免与其他代码中的相同名称的标识符发生冲突。这对于大型项目或多人协作的代码库非常重要。

    // 定义命名空间
    namespace MyNamespace {int myVariable;void myFunction();class MyClass { /* ... */ }
    }
    
  2. 组织和模块化代码: 命名空间使得代码更加模块化和易于组织。通过将相关的功能放置在同一个命名空间中,代码结构更加清晰,对于代码的理解和维护更加方便。

    // 在项目中的不同文件中使用同一个命名空间
    // File1.cpp
    namespace Math {int add(int a, int b);
    }// File2.cpp
    namespace Math {int subtract(int a, int b);
    }
    
  3. 防止全局污染: 将标识符限定在命名空间中,避免了全局命名空间的污染。这样有助于控制和隔离代码的影响范围。

    // 不使用命名空间的情况
    int globalVariable;// 使用命名空间
    namespace MyNamespace {int myVariable;
    }
    
  4. 版本控制: 在不同的版本中,可以使用命名空间来隔离和管理不同版本的功能或接口,以确保向后兼容性或易于升级。

    // Version 1
    namespace MyApp_v1 {void someFunction();
    }// Version 2
    namespace MyApp_v2 {void someFunction();void newFunction();
    }
    
  5. 解决命名冲突: 当使用第三方库或合作开发时,可能会遇到不同部分使用相同名称的情况。使用命名空间可以帮助解决这些命名冲突。

    // 第三方库的命名空间
    namespace ExternalLibrary {void commonFunction();
    }// 项目的命名空间
    namespace MyProject {void commonFunction();void myFunction();
    }
    

1.3 命名空间的访问

命名空间的成员可以通过作用域解析运算符 :: 进行访问。通过 :: 运算符,你可以指定要访问的命名空间的名称,从而使用其中的变量、函数或类等成员。

以下是一些命名空间访问的示例:

通过 MyNamespace::,我们可以访问命名空间 MyNamespace 中的变量、函数和类。这样的方式可以有效地避免全局命名冲突,同时使得代码更具可读性。

// 定义命名空间
namespace MyNamespace {int myVariable = 42;void myFunction() {// 函数定义}class MyClass {// 类定义}
}int main() {// 访问命名空间中的变量int value = MyNamespace::myVariable;// 访问命名空间中的函数MyNamespace::myFunction();// 访问命名空间中的类MyNamespace::MyClass myObject;return 0;
}

通过 NS1:: 和 NS2:: 分别指定了要访问的命名空间,从而区分了两个同名的变量。

namespace NS1 {int x;
}namespace NS2 {int x;
}int main() {// 访问不同命名空间中的同名变量int value1 = NS1::x;int value2 = NS2::x;return 0;
}

当你有一个嵌套的命名空间结构时。在这个示例中,OuterNamespace 是外层命名空间,InnerNamespace 是内层命名空间。通过作用域解析运算符 ::,我们可以访问这两个命名空间中的变量。value1 获取了外层命名空间的变量值,而 value2 获取了内层命名空间的变量值。

// 外层命名空间
namespace OuterNamespace {int outerVariable = 42;// 内层命名空间namespace InnerNamespace {int innerVariable = 10;}
}int main() {// 访问外层命名空间的变量int value1 = OuterNamespace::outerVariable;// 访问内层命名空间的变量int value2 = OuterNamespace::InnerNamespace::innerVariable;return 0;
}

二、C++输入&输出

C++ 中的输入和输出操作符是 <<(输出操作符)和 >>(输入操作符)。这些操作符用于在控制台或文件中进行输入和输出操作。

std 是C++标准库(Standard Library)的命名空间,coutcinendl 是C++标准库中命名空间std的对象,它们属于输入输出流相关的头文件 <iostream> 中的一部分。

输出操作符 <<

在C++中,<< 是输出流操作符,用于将右侧的数据插入到左侧的输出流中(通常是标准输出流,即屏幕)。std::cout 是标准输出流对象,<< 将数据输出到流中。多个 << 操作符可以串联使用,将多个数据输出到同一个流中。

#include <iostream>int main() {int number = 42;std::cout << "The value of number is: " << number << std::endl;return 0;
}

输入操作符 >>

在C++中,>> 是输入流操作符,用于从流中读取数据。std::cin 是标准输入流对象,>> 从流中读取数据并存储在 number 变量中。

#include <iostream>int main() {int number;std::cout << "Enter a number: ";std::cin >> number;std::cout << "You entered: " << number << std::endl;return 0;
}

换行符和刷新输出缓冲区

std::endl 是C++标准库中的一个操作符,用于表示换行符和刷新输出缓冲区。它实际上是一个函数模板,定义在头文件 中,并属于 std 命名空间。

使用 std::endl 可以在输出流中插入一个换行符,并确保输出缓冲区被刷新。刷新输出缓冲区是为了确保立即将输出内容显示在屏幕上,而不是等待缓冲区被填满或遇到显式的刷新操作。等效地,也可以使用 '\n' 来表示换行符。

#include <iostream>int main() {int number = 42;// 使用 std::endl 插入换行符并刷新输出缓冲区std::cout << "The value of number is: " << number << std::endl;return 0;
}

关键字 using

使用 using 关键字可以展开命名空间中的标识符,使其在代码中更直接可用,而不需要显式加上命名空间的前缀。

以下是使用 using 展开命名空间的示例:

#include <iostream>// 使用 using 展开命名空间
using namespace std;int main() {// std::cout 可以直接使用为 coutcout << "Hello, World!" << endl;return 0;
}

需要注意的是,虽然 using namespace std; 提供了方便,但在大型项目中或与其他库集成时,可能会引入潜在的命名冲突。为了避免这些问题,一种更安全的方式是只使用需要的特定标识符,而不是整个命名空间。例如:

#include <iostream>// 使用 using 展开需要的标识符
using std::cout;
using std::endl;int main() {// 直接使用展开后的标识符cout << "Hello, World!" << endl;return 0;
}

三、缺省参数

3.1 概念

缺省参数(default parameters)允许在函数声明中为一个或多个参数指定默认值。这意味着在调用函数时,如果没有提供相应的参数值,将使用该参数的默认值

void Func(int a = 0){cout << a << endl;
}int main(){Func();     // 没有传参时,使用参数的默认值Func(10);   // 传参时,使用指定的实参return 0;
}

3.2 缺省参数分类

函数的参数可以全部使用缺省参数,也可以部分使用缺省参数,实现全缺省参数和半缺省参数的效果。

全缺省参数:
printInfo 函数的所有参数都使用了缺省参数,可以在调用时不提供任何参数值,或者提供部分或全部参数值。

#include <iostream>// 函数声明时全部使用缺省参数
void printInfo(int a = 1, int b = 2, int c = 3);int main() {// 调用函数时不提供任何参数值,使用了所有参数的默认值printInfo();// 提供部分参数值printInfo(4);// 提供所有参数值,不使用默认值printInfo(7, 8, 9);return 0;
}// 函数定义时也使用全部缺省参数
void printInfo(int a, int b, int c) {std::cout << "a: " << a << ", b: " << b << ", c: " << c << std::endl;
}

半缺省参数:
半缺省参数必须从右往左依次来给出,不能间隔着

#include <iostream>// 函数声明时部分使用缺省参数
void printInfo(int a, int b = 2, int c = 3);int main() {// 调用函数时提供所有参数值,不使用默认值printInfo(7, 8, 9);// 提供部分参数值printInfo(4);// 调用函数时不提供任何参数值,使用了第一个参数的默认值printInfo();return 0;
}// 函数定义时也使用部分缺省参数
void printInfo(int a, int b, int c) {std::cout << "a: " << a << ", b: " << b << ", c: " << c << std::endl;
}

需要注意的是, 缺省参数应避免函数声明和定义中同时出现,当缺省参数在函数声明和定义中同时出现时,编译器会面临二义性的问题

如果缺省参数在函数声明和定义中同时出现:

  • 编译阶段:

    • 编译器首先会处理声明,其中包含缺省参数的值。这个信息在汇编代码中被保存。
    • 接着,编译器会处理定义,其中也包含缺省参数的值。
  • 链接阶段:

    • 链接器需要解析符号,即函数名和参数列表。但现在存在两个相同的函数符号,一个来自声明,一个来自定义。
    • 缺省参数的值在编译阶段已经确定,但由于声明和定义提供了相同的信息,链接器无法准确地选择应该使用哪个缺省参数的值。

因此,在声明和定义中同时出现缺省参数会导致链接阶段的二义性,编译器无法确定应该使用哪个值,从而引发错误。为了避免这种情况,建议在声明中指定缺省参数的值,而在定义中不再提供。这样,在链接阶段,编译器就能够使用声明中的默认值。


四、函数重载

概念

函数重载是指在同一个作用域内定义多个同名函数,但它们的参数列表 (包括参数的类型、顺序或数量)不同

#include <iostream>using namespace std;// 重载函数,按类型
void print(int x) {cout << "Integer: " << x << endl;
}void print(double x) {cout << "Double: " << x << endl;
}// 重载函数,参数个数不同
void display(int x) {cout << "Display Integer: " << x << endl;
}void display(int x, double y) {cout << "Display Integer and Double: " << x << ", " << y << endl;
}// 重载函数,参数顺序不同
void show(double x, int y) {std::cout << "Show Double and Integer: " << x << ", " << y << endl;
}void show(int x, double y) {cout << "Show Integer and Double: " << x << ", " << y << endl;
}int main() {// 函数按类型重载print(42);       // 调用第一个 print 函数print(3.14);     // 调用第二个 print 函数// 函数参数个数不同重载display(10);                   // 调用第一个 display 函数display(20, 3.5);              // 调用第二个 display 函数// 函数参数顺序不同重载show(2.5, 15);                 // 调用第一个 show 函数show(7, 4.2);                  // 调用第二个 show 函数return 0;
}

函数重载的原理

C++中使用名称修饰来实现函数重载。而在C语言中,并不使用名称修饰的方式,函数名是直接暴露的,因此C语言不支持函数重载

函数重载的编译阶段和链接阶段:

  1. 编译阶段:

    • 函数定义: 在源代码中,定义了多个同名但参数列表不同的函数,即进行函数重载。例如:

      void print(int x);
      void print(double x);
      
    • 名称修饰: 编译器在编译阶段根据函数的名称和参数列表生成唯一的名称修饰后的标识符。这个过程被称为名称修饰或符号修饰。

      • 例如,生成的标识符可能为 _Z5printi_Z5printd
    • 生成目标文件: 编译器将源代码编译成目标文件(通常是 .o 文件),其中包含了函数的名称修饰后的标识符。

  2. 链接阶段:

    • 符号表生成: 在链接阶段,链接器将汇总所有目标文件中的符号,创建一个符号表。符号表记录了函数和变量名与其对应的地址或标识符。

      • 符号表可能包含了 _Z5printi_Z5printd 这样的名称修饰后的标识符。
    • 解析函数调用: 当程序中有函数调用时,链接器查找符号表,尝试解析函数名。

      • 如果有一个唯一匹配的标识符,链接器确定正确的函数地址或标识符。
    • 写入可执行文件: 链接器将正确的函数地址或标识符写入最终的可执行文件中,确保在运行时能够正确调用相应的函数。

  3. 运行时:

    • 函数调用: 当程序运行时,根据函数调用,执行相应的函数。函数的具体实现取决于编译时和链接时确定的地址或标识符。

函数重载的过程涉及编译阶段和链接阶段:编译阶段中,编译器根据函数的名称和参数列表生成唯一的名称修饰后的标识符,汇总所有标识符并创建一个符号表;链接阶段中,链接器通过符号表解析函数调用,将正确的函数地址或标识符写入最终的可执行文件,确保在运行时能够正确调用相应的函数。


在这里插入图片描述
如果你喜欢这篇文章,点赞👍+评论+关注⭐️哦!
欢迎大家提出疑问,以及不同的见解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/422306.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

论文阅读:Vary论文阅读笔记

目录 引言整体结构图数据集构造Vary-tiny部分Document Data数据构造Chart Data构造Negative natural image选取 Vary-base部分 引言 论文&#xff1a;Vary: Scaling up the Vision Vocabulary for Large Vision-Language Models Paper | Github | Demo 许久不精读论文了&#x…

如何查看Linux CPU占有率

目录 1、top 2、htop 3、vmstat 4、mpstat 5、iostat 查看嵌入式设备CPU占有率是评估系统资源使用情况的重要方式。 在Linux系统中&#xff0c;有多种方法可以查看CPU占有率&#xff0c;这里介绍几种常用的命令行工具。 1、top 这是最常用的命令之一&#xff0c;它提供了…

Unity 编辑器篇|(十三)自定义属性绘制器(PropertyDrawer ,PropertyAttribute) (全面总结 | 建议收藏)

目录 1. 前言2. PropertyDrawer2.1 参数总览2.2 两种用途2.3 注意事项2.4 代码样例 3. PropertyDrawer与PropertyAttribute结合使用 1. 前言 在Unity中&#xff0c;PropertyDrawer和PropertyAttribute是两个重要的工具&#xff0c;它们主要用于自定义属性的显示和行为。Proper…

U-Boot 命令解析(一)

U-Boot 命令解析&#xff08;一&#xff09; 查询命令环境变量操作命令修改环境变量新建环境变量删除环境变量&#xff0c; 内存操作命令内存查看命令 md内存修改命令 nm内存修改命令 mm内存填充命令 mw内存拷贝命令 cp内存对比命令 cmp 更多内容 一般情况下&#xff0c;U-Boot…

亚马逊KYC审核的重要性,所需提交的文件有哪些?—站斧浏览器

亚马逊KYC审核的重要性有哪些&#xff1f; KYC审核是亚马逊对卖家身份的一种验证&#xff0c;确保卖家遵守相关法规。只有通过审核的卖家才能在欧洲平台进行销售。因此&#xff0c;正确理解和应对KYC审核对于卖家来说至关重要。 注册完成后立即触发&#xff1a;新注册的卖家可…

const关键字

修饰常量 const int a 10; int const a 10; 常量指针 以下两种方式等价 const int *a; int const *a; 常量指针说的是不可以通过指针改变指向内容的值&#xff0c;但是可以重新指向新的地址, 因此一般用作函数参数&#xff0c;防止内部通过指针地址中保存的值void test(…

Netty篇章(1)—— 核心原理介绍

终于进入到Netty框架的环节了&#xff0c;前面介绍了大量的Java-NIO的内容&#xff0c;核心的内容Selector、Channel、Buffer、Reactor掌握了&#xff0c;那么学起来Netty也是水到渠成的事情。如果没有掌握前面的内容那么学Netty会非常吃力&#xff0c;下面讲解Netty核心原理与…

机械设计-哈工大课程学习-螺旋传动

二、摩擦类型 1、静态摩擦&#xff1a;这是身体静止时所经历的摩擦。换句话说&#xff0c;就是身体有运动倾向时的摩擦力。 2、动态摩擦&#xff1a;这是身体在运动时所经历的摩擦。也称为动摩擦。动摩擦有以下两种类型&#xff1a; ①滑动摩擦&#xff1a;一个物体在另一个…

【深蓝学院】移动机器人运动规划--第2章 基于搜索的路径规划--笔记

0. Outline 1. Graph Search Basis Configuration Space等概念 机器人配置: 指机器人位置和所有点的表示。 DOF: 指用于表示机器人配置所需的最小的实数坐标的数量n。 C-space: 包含机器人n维所有配置的空间。 在C-space中机器人的pose是一个点。 机器人在C-space中被表示为一…

stm32中的SPI

SPI的简介 文章目录 SPI的简介物理层协议层基本通讯过程起始和终止信号数据有效性CPOL/CPHA及通讯模式 STM3的SPI特性及架构通讯引脚时钟控制逻辑数据控制逻辑整体控制逻辑通讯过程 代码配置实现结构体的定义SPI时钟信号的定义SPI端口定义SPI命令 flash驱动代码初始化代码(配置…

算法基础学习|双指针算法

双指针算法 代码模板 for (int i 0, j 0; i < n; i ){while (j < i && check(i, j)) j ;// 具体问题的逻辑 } 常见问题分类&#xff1a;(1) 对于一个序列&#xff0c;用两个指针维护一段区间(2) 对于两个序列&#xff0c;维护某种次序&#xff0c;比如归并…

Day34 1005k次取反最大值 134加油站 135分发糖果

1005 k次取反最大值 给定一个整数数组 A&#xff0c;我们只能用以下方法修改该数组&#xff1a;我们选择某个索引 i 并将 A[i] 替换为 -A[i]&#xff0c;然后总共重复这个过程 K 次。&#xff08;我们可以多次选择同一个索引 i。&#xff09; 以这种方式修改数组后&#xff0…