C++学习之路,从0到精通的征途:入门基础

目录

一.C++的第一个程序

二.命名空间

1.namespace的价值

2.命名空间的定义

3.命名空间使用

三.C++的输入与输出

1.<iostream>

2.流

3.std(standard)

四.缺省参数 

1.缺省参数的定义

 2.全缺省/半缺省

3.声明与定义

​五.函数重载

1.参数个数不同

2.参数类型不同

3.参数类型顺序不同

函数返回值不同是否能作为重载条件?

带有缺省参数的函数能构成重载吗?

六.引用

1.引用的概念和定义

2.引用的特性  

2.1引用在定义是必须初始化

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

2.3引用一旦引用一个实体,再不能引用其他实体 

3.引用的使用

3.1引用传参

3.2引用作返回值

4.const引用

5.指针和引用的关系

七.inline

 1.inline的定义与概念

2.inline的特性

3.inline与宏函数的比较

八.nullptr

九.总结 


一.C++的第一个程序

        第一个程序当然是“Hello World”,不过这里我们使用C++的语法进行实现。

        在实现前,我们创建的文件必须得是.cpp文件,编译器在识别后缀为.cpp后才会调用C++编译器,这里后缀改为.c文件是会报错的。

#include<iostream>
using namespace std;

int main()
{
	cout << "Hello World" << endl;
	return 0;
}

运行结果:

        这里对于代码有疑问是正常的,接下来我们来逐一讲解。

二.命名空间

1.namespace的价值

        在C语言中如果一个声明的变量名刚好与其他变量名重复或者与函数名等重复,则会出现报错,例如下面这段代码:

#include<stdio.h>
#include<stdlib.h>

int rand = 0;

int main()
{
	
	printf("%d\n", rand);
	return 0;
}

报错片段:

        可以看到报错语句为重定义:以前的定义是函数。

        在这里我们期望rand是int类型,但rand是函数类型,这说明由于stdlib.h中rand()的存在,编译器将rand识别为了函数,在C语言中如果要解决这样的问题只能再取一个其他变量名,但在C++中我们可以用命名空间去解决命名冲突的问题。

2.命名空间的定义

        定义命名空间,需要用到关键字namespace,后面跟命名空间的名字,这里用mySpace举例,再跟一对大括号{},{}中可以定义命名空间的成员,成员可以是变量/函数/类型等。

代码演示:

namespace mySpace
{
	int rand = 0;

	int Add(int left, int right)
	{
		return left + right;
	}

	struct Node
	{
		struct Node* next;
		int val;
	};
}

        namespace本质是定义一个域,在C语言中由于不用域中可以定义同名变量,namespace也类似与这种特性,namespace定义的域与全局域各自独立,其通过域隔离解决了同名冲突的问题,且命名空间不会影响变量的生命周期。

        命名空间只能定义在全局,同时namespace也可以嵌套定义。

代码演示:

namespace mySpace
{
	namespace s1
	{
		int rand = 0;
		int a = 1;
	}

	namespace s2
	{
		int rand = 10;
		int a = 11;
	}
}
	printf("%d\n", mySpace::s1::a);
	printf("%d\n", mySpace::s2::a);

        在调用的过程中,我们使用域作用限制符::,它能在编译时通过指定域的形式进行查找。

        如第一条printf语句,就是访问MySpace中命名空间s1中的整型变量a,打印值为1。

运行结果:

·        在项目目工程文件中,同名的namespace会认为是一个namespace不会冲突:

·        我们再定义一个头文件,并创建一个同名namespace。

        

        在包含头文件后可以看到,程序并未报错,并成功输出b的值,这说明编译器认为两个namespace并不冲突,为同一个命名空间。

3.命名空间使用

         编译器的查找规则为: 1.先局部再全局        2.指定域中查找

        所以如果直接查找命名空间中的变量名而并未指定,则会报错,参考下面程序:

        如果要正确使用命名空间中定义的变量/函数,有三种方式:

        1.运用域作用限制符,指定命名空间访问,项目中推荐使用。

        2.使用using将命名空间中某个频繁使用的变量/函数展开,项目中不推荐使用。

        这样就可以让上面的程序不报错了,但由于将命名空间中的a展开,可能会有同名冲突的风险。
        3.用using展开命名空间中的所有成员项目中不推荐,冲突风险大,日常练习时方便推荐使用。

三.C++的输入与输出

1.<iostream>

        C++中的输入与输出不再使用<stdio.h>,而是用<iostream>,iostream是Input Output Stream 的缩写,库中定义了标准的标准的输入输出对象,其中包含<iostream>也会间接包含<stdio.h>,所以也能使用printf和scanf,不同编译器可能会报错。

2.流

        std::cin 是 istream 类的对象,它主要面向窄字符(narrow characters (of type char))的标准输入流。

        std::cout 是 ostream 类的对象,它主要面向窄字符的标准输出流。

        std::endl 是⼀个函数,流插入输出时,相当于插入一个换行字符加刷新缓冲区。现在可以简单理解为换行符。  

        <<是流插入运算符,>>是流提取运算符。(C语言中用这两个运算符做位运算左移/右移)

示例:

        C++中的输入输出不再需要像C语言那样手动指定格式,流可以自动识别变量类型,也能更好的支持自定义类型的输入输出。

例如:

3.std(standard)

        C++的标准库放在一个为std的命名空间中,cout/cin/endl都属于标准库,所以需要通过命名空间std去使用他们。   

        与命名空间的使用方式相同:

        1.域作用操作符,指定命名空间访问

	std::cin >> a;
	std::cout << a << std::endl;

        2.using展开频繁使用的成员

#include<iostream>
using std::cout;
using std::endl;

int main()
{
	int a = 0;
	std::cin >> a;
	cout << a << endl;

	return 0;
}

        3.using展开命名空间,项目中不推荐使用,推荐日常练习

using namespace std;

四.缺省参数 

1.缺省参数的定义

        缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。调用该函数时,如果并未传输指定的实参,则直接采用缺省值,否则使用指定的实参,缺省参数分为全缺省和半缺省参数。(有些地方把缺省参数也叫默认参数)

如图:

 2.全缺省/半缺省

        全缺省就是所有形参给缺省值,示例:

        半缺省就是部分下形参给缺省值,示例:

        由于这里是半缺省,a没有缺省值,所以在调用函数时必须传至少一个参数。                

        同时C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值。

报错片段:

        带有缺省参数的函数调用,传参时不可跳跃,必须从左到右依次给实参。

3.声明与定义

        带有缺省参数的函数在声明和定义分离时,不能同时给缺省参数,规定必须在声明中出现。

五.函数重载

        C++中支持在同一作用域下同名函数的出现,但必须这些函数的形参个数不同,形参类型不同,或形参类型顺序不同,这样可以让函数调用呈现多态行为,更加灵活。

1.参数个数不同

2.参数类型不同

3.参数类型顺序不同

函数返回值不同是否能作为重载条件?

        由于函数名和参数相同,在调用函数时无法根据返回值的不同来区分到底要调用哪个函数,所以会报错,显示函数f重定义

        所以函数返回值不同并不能作为重载条件。

带有缺省参数的函数能构成重载吗?

        可以看到报错语句为对重载函数的调用不明确,说明带有缺省参数的函数构成重载,但在函数调用时,编译器不知道调用的是哪个函数,存在歧义,所以会导致报错。

六.引用

1.引用的概念和定义

        引用不是定义一个新变量,而是给已有的变量取一个别名,编译器不会为引用变量开辟空间,引用变量与被引用的变量使用同一块内存空间。

类型& 引用别名 = 引用对象

	int a = 0;

	int& b = a;
	int& c = a;

        b,c是变量a的别名。这里引用符号&与取地址符号相同,根据用法区分即可。

    int& d = b;

        也可以给别名b取别名为d,所以d也是a的别名         

      由于b,c,d是a的别名,四者同用一块内存空间,在++d后,a,b,c,d的值全部自增一,并且从运行结果可以看出四个变量的地址相同,共用一块空间。 

2.引用的特性  

2.1引用在定义是必须初始化

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

2.3引用一旦引用一个实体,再不能引用其他实体 

3.引用的使用

        引用在实际操作中主要用来作引用传参引用作返回值,从而减少拷贝,提高效率,在改变引用对象的同时改变被引用对象。

3.1引用传参

        引用传参指针传参类似,但理解和使用更加简单和方便,以Swap函数举例:

void Swap(int& x, int& y)
{
	int tmp = x;
	x = y;
	y = tmp;
}

运行结果:

        可以看到a,b交换了值,但与指针不同的是函数体里无需解引用操作,因为引用对象与被引用对象使用的是同一块内存空间,直接交换即可。

3.2引用作返回值

        为了更好的举例,在这里我们添加数据结构栈的头文件和源文件,代码详细参考:栈:数据结构中的“时间管理大师” 

        可以看到在让栈顶加10的操作中出现了报错,报错提示为StackTop(&st)不是左值,说明此时栈顶不可被修改,为右值

分析:

              

        在函数返回时,操作系统会将返回值储存在一个临时对象中,再将临时对象中的值返回,因为这个临时对象具有常性,所以栈顶不能被修改。那如何才能让这个操作合法呢?

        在这里我们将引用作返回值,并将参数优化为引用参数

// 获取栈顶元素 
STDataType& StackTop(Stack& ps)
{
	assert(ps._top > 0);
	return ps._a[ps._top - 1];
}

        此时函数栈帧销毁后,返回对象top并不是存在临时对象中,即函数栈帧销毁对返回其引用并无影响,故此时栈顶可修改。

        为了更深刻的理解引用作返回值的情况,再举一个示例:

        这里可以看到,虽然编译器并未报错,但是返回值并未加10,由于ret存在于函数栈帧中,出函数后,ret也销毁了,所以返回引用结果出现问题。

        对于引用返回,函数栈帧结束后,如果返回对象在函数栈帧中,返回引用就会出现问题,如果返回对象不在函数栈帧中,可以正常返回其引用。

4.const引用

        可以引用一个const对象,但引用也必须为const,对于普通对象也可以进行const引用,因为对象的访问权限在引用过程中只可以缩小,不能放大。

        在类型转换中的const引用:

        由于在类型转换时,操作系统会创建临时对象,临时对象具有常性,所以在转换时需要用const引用接收。

临时对象:

        所谓临时对象就是编译器需要⼀个空间暂存表达式的求值结果时临时创建的⼀个未命名的对象, C++中把这个未命名对象叫做临时对象

        临时对象在以下三种常用情况下会创建:

        1. 函数传值返回

        2.表达式运算

        3.类型转换

5.指针和引用的关系

        指针与引用在实践中相辅相成,在功能上有重叠性,但都有各自的特点,互相不可替代。

七.inline

 1.inline的定义与概念

        被inline修饰的函数叫做内联函数,在编译时C++编译器会在调用的地方展开内联函数,这样调用内联函数时就不需要创建函数栈帧了,提高了效率。

2.inline的特性

        inline适用于频繁调用的短小函数,对于递归函数,代码量较多的函数加上inline也会被编译器忽略。

        通过该段代码的汇编可以看到,在调用内联函数Swap时,并没有call指令,说明Swap函数在调用中已展开,根据右边的汇编代码可以进一步验证。

        inline不建议声明和定义分离到两个文件,分离会导致链接错误,因为inline被展开,就没有函数地址,链接时会报错。

3.inline与宏函数的比较

        先来看一段宏函数:

        对于这个宏函数,为了巩固理解,需要回答下面三个问题: 

        1.为什么要加分号?

        宏函数是在预处理时,将语句整体替换到调用处,如果加了分号,分号也会一并调换。

        2.为什么加外面的括号?

        宏函数在与其他式子作运算时需要考虑优先级的问题,加了外面的括号,保证宏函数优先级更高。

        3.为什么加里面的括号?

        a,b各自为一个表达式,加了里面的括号,保证表达式的优先运算。

        从这三个问题可以看出宏函数的实现很复杂,且很容易出错,不方便调试,所以C++中设计inline的目的就是为了替代宏函数,在提高效率的同时,更容易实现,不过与宏不同的是,inline的展开是在编译而不是预处理阶段,使其更容易调试。

八.nullptr

        NULL实际是一个,在传统的C头文件(stddef.h)中,可以看到如下代码:

#ifndef NULL
	#ifdef __cplusplus
		#define NULL 0
	#else
		#define NULL ((void *)0)
	#endif
#endif

        所以在C++中NULL可能会被定义为字面常量0,在下面这种情况下,与程序的初衷违背:

        这里func(NULL)的目的是调用func(int* ptr),但却由于NULL被定义成了数字常量0,调用成了func(int x),所以如果要调用func(int* ptr),还得对NULL强转类型:

        但强转类型只能让NULL强转一种类型,无法应对变量的多种类型,所以C++在这里引入了一个关键字:nullptr它可以转换成任意其他类型的指针类型。使用nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被隐式地转换为指针类型,而不能被转换为整数类型。

示例:

九.总结 

        C++ 的这些基础内容,是踏上这门强大编程语言之旅的重要一步。从第一个程序的 “Hello, World!” 开始,我们逐步揭开了命名空间、输入输出、缺省参数、函数重载、引用、inline函数以及 nullptr 等关键概念的神秘面纱。这些知识相互关联,共同构成了 C++ 编程的基石。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

rust学习笔记12-hashmap与1. 两数之和

rust集合中也有hashmap&#xff0c;昨天已经提到过&#xff0c;学过java同学再熟悉不过了&#xff0c;一道经典面试题问hashmap在java1.8的实现原理&#xff0c;数组哈希表红黑树&#xff0c;rust中hashmap在功能上和java一样&#xff0c;但实现上有很大差别&#xff0c;它的基…

通过多线程同时获取H264和H265码流

目录 一.RV1126 VI采集摄像头数据并同时编码H264、H265的大概流程​编辑​编辑 1.1初始化VI模块&#xff1a; 1.2H264、H265的VENC模块初始化&#xff1a; 1.3VI分别绑定H264的VENC层和H265的VENC层&#xff1a; ​​​​​​​1.4开启H264线程采集H264的VENC数据&#xff…

SpringBoot为什么要禁止循环依赖?

大家好&#xff0c;我是锋哥。今天分享关于【SpringBoot为什么要禁止循环依赖?】面试题。希望对大家有帮助&#xff1b; SpringBoot为什么要禁止循环依赖? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring Boot 和 Spring 框架之所以要避免循环依赖&#xf…

The Rust Programming Language 学习 (三)

所有权 所有权&#xff08;系统&#xff09;是 Rust 最为与众不同的特性&#xff0c;它让 Rust 无需垃圾回收器&#xff08;garbage collector&#xff09;即可保证内存安全。因此&#xff0c;理解 Rust 中所有权的运作方式非常重要。 这里是非常重非常重的一个知识点,这里一…

基于物联网技术的电动车防盗系统设计(论文+源码)

1总体设计 本课题为基于物联网技术的电动车防盗系统&#xff0c;在此将整个系统架构设计如图2.1所示&#xff0c;其采用STM32F103单片机为控制器&#xff0c;通过NEO-6M实现GPS定位功能&#xff0c;通过红外传感器检测电瓶是否离开位&#xff0c;通过Air202 NBIOT模块将当前的数…

雷池WAF的为什么选择基于Docker

Docker 是一种开源的容器化平台&#xff0c;可以帮助开发人员将应用程序及其所有依赖项打包到一个称为容器的独立、可移植的环境中。Docker 的核心概念包括以下几点&#xff1a; 容器&#xff1a;Docker 使用容器来封装应用程序及其依赖项&#xff0c;使其能够在任何环境中都能…

解决docker认证问题 failed to authorize: failed to fetch oauth token

报错信息[bash1]解决方案 全局代理打开“buildkit”: false &#xff0c;见[图1] [bash1] >docker build -t ffpg . [] Building 71.8s (3/3) FINISHED docker:desktop-linux> [internal] load bui…

LINUX网络基础 [一] - 初识网络,理解网络协议

目录 前言 一. 计算机网络背景 1.1 发展历程 1.1.1 独立模式 1.1.2 网络互联 1.1.3 局域网LAN 1.1.4 广域网WAN 1.2 总结 二. "协议" 2.1 什么是协议 2.2 网络协议的理解 2.3 网络协议的分层结构 三. OSI七层模型&#xff08;理论标准&#xff09; …

【Docker】容器安全之非root用户运行

【Docker】容器安全之非root用户运行 1. 场景2. 原 Dockerfile 内容3. 整改结果4. 非 root 用户带来的潜在问题4.1 文件夹读写权限异常4.2 验证文件夹权限 1. 场景 最近有个项目要交付&#xff0c;第三方测试对项目源码扫描后发现一个问题&#xff0c;服务的 Dockerfile 都未指…

亚马逊云科技Marketplace(中国区)上架专业服务产品, “云生态连接器”价值凸显

近日&#xff0c;由西云数据运营的亚马逊云科技Marketplace&#xff08;中国区&#xff09;正式支持专业服务产品。此次发布将大幅简化企业对云专业服务的采购流程&#xff0c;实现云软件从规划、部署到支持的全生命周期管理&#xff0c;同时也为合作伙伴提供了更多的销售机会。…

鸿蒙启动页开发

鸿蒙启动页开发 1.1 更改应用名称和图标 1.更改应用图标 找到moudle.json5文件&#xff0c;找到应用启动的EntryAbility下面的icon,将原来的图标改成自己设置的即可 2.更改应用名称 3.效果展示 2.1 广告页面开发 3.1 详细介绍 3.1.1 启动页面 import { PrivacyDialog } fr…

HCIA—IP路由静态

一、概念及作用 1、概念&#xff1a;IP路由是指在IP网络中&#xff0c;数据从源节点到目的节点所经过的路径选择和数据转发的过程。 2、作用 ①实现网络互联&#xff1a;使不同网段的设备能够相互通信&#xff0c;构建大规模的互联网络 ②优化网络拓扑&#xff1a;根据网络…

【计算机网络入门】初学计算机网络(十一)重要

目录 1. CIDR无分类编址 1.1 CIDR的子网划分 1.1.1 定长子网划分 1.1.2 变长子网划分 2. 路由聚合 2.1 最长前缀匹配原则 3. 网络地址转换NAT 3.1 端口号 3.2 IP地址不够用&#xff1f; 3.3 公网IP和内网IP 3.4 NAT作用 4. ARP协议 4.1 如何利用IP地址找到MAC地址…

机器视觉开发教程——封装Halcon通用模板匹配工具【含免费教程源码】

目录 引言前期准备Step1 设计可序列化的输入输出集合【不支持多线程】Step2 设计程序框架1、抽象层【IProcess】2、父类【HAlgorithm】3、子类【HFindModelTool】 Step3 设计UI结果展示 引言 通过仿照VisionPro软件二次开发Halcon的模板匹配工具&#xff0c;便于在客户端软件中…

【Linux跬步积累】—— 线程池详解(有源代码)

文章目录 一、如何实现一个线程1、基本结构2、实现成员函数3、演示4、代码总汇Thread.hppMain.cc 二、如何封装线程池1、设计成员变量2、构造函数与析构函数3、初始化4、启动与回收5、主线程放入任务6、子线程读取任务7、终止线程池 三、测试四、线程池总代码1、ThreadPool.hpp…

【Linux】自定协议和序列化与反序列化

目录 一、序列化与反序列化概念 二、自定协议实现一个加法网络计算器 &#xff08;一&#xff09;TCP如何保证接收方的接收到数据是完整性呢&#xff1f; &#xff08;二&#xff09;自定义协议 &#xff08;三&#xff09;自定义协议的实现 1、基础类 2、序列化与反序列…

hive之LEAD 函数详解

1. 函数概述 LEAD 是 Hive 中的窗口函数&#xff0c;用于获取当前行之后指定偏移量处的行的值。常用于分析时间序列数据、计算相邻记录的差异或预测趋势。 2. 语法 LEAD(column, offset, default) OVER ([PARTITION BY partition_column] [ORDER BY order_column [ASC|DESC]…

ZYNQ-PL学习实践(二)按键和定时器控制LED闪烁灯

ZYNQ-PL学习实践&#xff08;二&#xff09;按键和定时器控制LED闪烁灯&#xff09; 1 创建工程2 verilog 代码3 约束4 综合5 生成bit总结 1 创建工程 2 verilog 代码 添加key_led.v 文件&#xff0c; module key_led(input sys_clk , //系统时钟50MHzinput …

【Python爬虫】利用代理IP爬取跨境电商AI选品分析

引言 随着DeepSeek的流行&#xff0c;越来越多的用户开始尝试将AI工具融入到日常工作当中&#xff0c;借助AI的强大功能提高工作效率。最近又掀起了一波企业出海的小高潮&#xff0c;那么如果是做跨境电商业务&#xff0c;怎么将AI融入工作流中呢&#xff1f;在做跨境电商的时候…

设计一个SVF下载器之一:整体思路

CPLD或者FPGA开发工具会生成SVF文件用以通过JTAG口配置CPLD或者FPGA。这里有些基本控制JTAG状态机的指令&#xff0c;其实就是主要两条SIR和SDR分别实现对IR寄存器和DR寄存器的写。 这样我们的这个下载器的基本工作变成了解析SVF文件之后对JTAG的TAP状态机进行操作实现对IR和D…