【C++初阶】C++入门

1、C++第一个程序

C++是脱胎于C语言的,所以也包含了C语言绝大多数的内容,C++兼容C语言绝大多数的语法,在C语言中能实现的程序在C++中也是可以执行的,但需要将定义文件代码的后缀改为.cpp

就比如hello world程序

// test.cpp
#include<stdio.h>
int main()
{
printf("hello world\n");
return 0;
}

但在C++中,它是自成体系的,有自己的输入输出 c++版的hello world程序为

#include<iostream>
using namespace std;int main()
{cout<<"hello world\n"<<endl;return 0;
}
初学C++的小伙伴出看见这个代码会有很多疑惑,但不要慌张,接下来让我来为你详细解释

2、命名空间:namespace

在看很多书上的C++代码都很看到这样的一行代码“using namespace std;”,

都会疑惑namespace是什么?在这里有什么作用?
不要急,我们慢慢来

我们要知道在C语言中我们经常会因为变量和函数的命名冲突而感到困惑,而我们的C++的祖师爷可能也是深受它的毒害吧,就创造了一个新概念,叫做命名空间(namespace)

使用命名空间的目的就是对标识符的名称进⾏本地化,以避免命名 冲突或名字污染namespace关键字的出现就是针对这种问题的

namespace的定义

1、

定义命名空间,需要使⽤到namespace关键字,后⾯跟命名空间的名字,然后接⼀对{}即可,{}中

即为命名空间的成员。命名空间中可以定义变量/函数/类型

namespae 空间名
{}

命名空间的本质,在C语言中我们学过了全局域和局部域,而我们在C++中学习的命名空间这个域独立于全局域,又因为不同的域可以定义同名的变量,在这里我们也可以知道,命名空间域中的变量也和全局变量一样,只有在程序结束后才会结束生命周期

总结就是:命名空间域内的变量和全局变量类似
命名空间会影响编译查找变量的规则,使得C++中查找规则是:先查找局部域,在查找全局域,一般不会在命名空间中查找

2、

namespace只能定义在全局域中,而且它还可以嵌套定义:就是在一个namespace中再定义一个namespace(可以无限套娃,但最多嵌套两三次就足够了)

这里的嵌套定义就类似于一个公司里面有很多部门,每个部门就相当于一个namespace,而每个部门里面又有很多员工,每个员工又是一个独立的namespace

嵌套定义后使用命名空间就需要由外向里的进行寻找

3、

多个文件中定义了多个同名的namespace的时候,并不会发生冲突,它会自动合并为一个命名空间

4、

C++的标准库都放在std的命名空间中,这就是为什么许多C++代码都会有“using namespace std;

namespace的使用

1、指定命名空间访问(项目中推荐使用)
2、using将命名空间中的某个成员展开,这适用于项目中经常使用而且不存在冲突的成员
3、using将命名空间中全部的成员展开,这种方法在项目中不推荐使用,而且当出现多个using的展开可能会出现冲突
using n::b;
int main()
{printf("%d ",n::a);//指定命名空间访问 printf("%d ",b);//using将命名空间中的某个成员展开   return 0;
}

using namespace n;//展开命名空间中的全部成员int main()
{printf("%d",a);return 0;
}

3、C++的输入输出

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

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

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

std::endl 是⼀个函数,流插⼊输出时,相当于插⼊⼀个换⾏字符加刷新缓冲区。

<<是流插⼊运算符,>>是流提取运算符。(C语⾔还⽤这两个运算符做位运算左移/右移)

使⽤C++输⼊输出更⽅便,不需要像printf/scanf输⼊输出时那样,需要⼿动指定格式,C++的输⼊

输出可以⾃动识别变量类型(本质是通过函数重载实现的,这个以后会讲到),其实最重要的是

C++的流能更好的⽀持⾃定义类型对象的输⼊输出。

IO流涉及类和对象,运算符重载、继承等很多⾯向对象的知识,这些知识我们还没有讲解,所以这

⾥我们只能简单认识⼀下C++ IO流的⽤法,后⾯我们会有专⻔的⼀个章节来细节IO流库。

cout/cin/endl等都属于C++标准库,C++标准库都放在⼀个叫std(standard)的命名空间中,所以要 通过命名空间的使⽤⽅式去⽤使用它们

4、缺省参数(默认参数)

缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值,也就是给函数的形参一个默认值。在调用该函数时,如果没有给明实参就采用该形参的默认值(缺省值)否则就使用给明的实参

缺省参数又分为全缺省半缺省参数
全缺省:函数的全部形参都给缺省值
半缺省:就是部分形参给缺省值

C++规定半缺省参数必须从右往左依次连续缺省,不能中间跳跃给实参;而且带缺省参数的函数调用时,C++规定必须从左往右依次给实参,不能跳跃给实参

缺省参数不能在函数声明和定义中同时出现,且规定必须函数声明给缺省值
#include <iostream>
using namespace std;void Func(int a = 0)
{cout << a << endl;
}
int main()
{Func(); // 没有传参时,使⽤参数的默认值Func(10); // 传参时,使⽤指定的实参return 0;
}

#include <iostream>
using namespace std;
// 全缺省
void Func1(int a = 10, int b = 20, int c = 30)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl << endl;
}
// 半缺省
void Func2(int a, int b = 10, int c = 20)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl << endl;
}
int main()
{Func1();Func1(1);Func1(1,2);Func1(1,2,3);Func2(100);Func2(100, 200);Func2(100, 200, 300);return 0;
}

5、函数重载

C++⽀持在同⼀作⽤域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者 类型不同。这样C++函数调⽤就表现出了多态⾏为,使⽤更灵活。C语⾔是不⽀持同⼀作⽤域中出现同名函数的。

函数重载主要是根据形参来进行区别
1、形参类型不同
2、形参个数不同
3、形参顺序不同
#include<iostream>
using namespace std;
// 1、参数类型不同
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;
}
// 2、参数个数不同
void f()
{cout << "f()" << endl;
}
void f(int a)
{cout << "f(int a)" << endl;
}
// 3、参数类型顺序不同
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;
}

这里要注意的是返回值不同的同名函数不构成重载,编译器无法进行区分

int f(int a)
{cout << "f(int a)" << endl;return 0;
}void f(int a)
{cout << "f(int a)" << endl;
}int main()
{f(10);f();return 0;
}

在多个同名函数中,其中有函数中含有缺省参数时我,虽然在传参时构成重载,但是在不传参时会发生编译错误,因为编译器不知道应该调用哪个函数(这里就涉及到了二义性

void f1()
{cout << "f()" << endl;
}
void f1(int a = 10)
{cout << "f(int a)" << endl;
}
int main()
{f();f(10);return 0;
}

6、引用

C++中引入了一个新的概念叫做:引用,引用顾名思义就是用别人的,而不是自己的,所以,引⽤不是新定义⼀个变量,⽽是给已存在变量取了⼀个别名,编译器不会为引⽤变量开辟内存空间,它和它引⽤的变量共⽤同⼀块内存空间(在这里是是指代语法层)。

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

引用的特性

1、引用在定义时必须初始化;

2、一个变量可以有多个引用;

3、引⽤⼀旦引⽤⼀个实体,再不能引⽤其他实体

int main()
{int a = 0;// 引用:b和c是a的别名int& b = a;int& c = a;// 也可以给别名b取别名,d相当于还是a的别名int& d = b;++d;// 编译报错:“ra”: 必须初始化引用//int& ra;int* c = &a;int*& rc = c;//指针也可以取别名// 这里取地址我们看到是一样的cout << &a << endl;cout << &b << endl;cout << &c << endl;cout << &d << endl;int x = 10;d = x;//在这里是赋值拷贝return 0;
}

引用的使用

引用的实践主要是在引用传参引用做返回值两个方面

引用传参:

引用传参跟指针传参功能是类似的,它其实就是代替了指针的传址,而且也不需要像指针一样要解引用和取地址,并且引用不需要开辟空间,减少了拷贝,极大地提高了效率

//引用传参
void Swap(int& ra, int& rb)
{int temp = ra;ra = rb;rb = temp;
}
int main()
{int a = 1, b = 2;printf("a=%d,b=%d\n", a, b);Swap(a, b);printf("a=%d,b=%d\n", a, b);return 0;
}

引用做返回值:

引用做返回值本质是:不会生成临时变量,直接返回对象别名(这里的别名指的是给被引用对象所处空间起的别名)
在引用做函数返回值时,函数结束后函数栈帧会被销毁,却不会影响实参及其别名所处的空间,所以用引用做返回就能起到指针传址调用一样的作用,改变实参

typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;
void STInit(ST& rs, int n = 4)//在这里也是用到引用传参
{rs.a = (STDataType*)malloc(n * sizeof(STDataType));rs.top = 0;rs.capacity = n;
}// 栈顶
void STPush(ST& rs, STDataType x)
{//assert(ps);// 满了, 扩容if (rs.top == rs.capacity){printf("扩容\n");int newcapacity = rs.capacity == 0 ? 4 : rs.capacity * 2;STDataType* tmp = (STDataType*)realloc(rs.a, newcapacity *sizeof(STDataType));if (tmp == NULL){perror("realloc fail");return;}rs.a = tmp;rs.capacity = newcapacity;}rs.a[rs.top] = x;rs.top++;
}
/*引用做返回值*/
int& STTop(ST& rs)
{//assert(rs.top > 0);return rs.a[rs.top - 1];
}int main()
{ST s;STInit(s);STPush(s, 1);STPush(s, 2);STPush(s, 3);STPush(s, 4);//传值/*int top = STTop(s);top+=10;cout << top << endl;*///引用传参/*STTop(s) += 10;cout << STTop(s) << endl;*/return 0;
}

在这里是使用传值返回,在C/C++中规定,返回类型除引用以外,返回对象是先存储在一个临时变量(或者寄存器)当中,再由临时变量传到主函数中,临时变量的建立需要开辟空间,再由主函数中建立一块空间接收,所以主函数中就需要在建立一个同类型变量接收临时变量的值 

/*传值*/
int STTop(ST& rs)
{return rs.a[rs.top - 1];
}

错误示范,不能返回局部对象的引用 

在该函数结束后,函数栈帧销毁,top也会被销毁,这时的别名就会像free(指针)后,没有给指针置空一样,成为野别名
虽然编译器不会报错,但是也无法实现功能

int& STTop(ST& rs)
{int top = rs.a[rs.top - 1];return top;
}

const引用

可以引用一个const对象,但必须const引用,这里就涉及了权限的平移const->const

const int a=1;
const int& ra=a;//权限的平移

const引用也可以引用普通对象,这里就涉及了权限的缩小由变量变为常量

int a=10;
const int& ra=a;
//权限的缩小

但权限不能放大

const int& a=1;
int& ra=a;//错误

在对象权限的访问中,权限可以平移、缩小,但不能放大 ,这里的对象指的是指针和引用

临时变量(临时对象 )

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

C++中把这个未命名对象叫做临时对象

被引用对象为常量表达式类型不同(会涉及到类型转换)时要用到临时变量,而C++规定临时对象具有常性,所以这⾥就触发了权限放⼤,必须要⽤常引⽤(const才可以。

int main()
{//临时变量的常性(具有const的属性)//常量//int& x = 10;//错误的,要引用一个常量,就要在前面加一个constconst int& x = 10;cout << x << endl;//表达式int p = 2;//错误//int& rp = p*2;//在这里就涉及到了临时变量//p*2的和存储在一个临时变量里面,而临时变量具有const属性,//所以接收值也应该具有const属性,就需要在前面加一个const(都是涉及权限的放大)const int& rp = p*3;cout << rp << endl;//类型不同double d = 1.1;//int& rd = d;//在这里值也是存储在一个临时变量当中,所以也要用const来接收(都是涉及权限的放大)const int& rd = d;cout << d << endl;return 0;
}

当我们在函数传参,用到引用的时候,传入的值就如上面的三种情况时就需要用const引用了 

在现在学习到的场景下,类型转换传值返回会用到临时对象

指针与引用的关系

C++中指针和引⽤就像两个性格迥异的亲兄弟,指针是哥哥,引⽤是弟弟,在实践中他们相辅相成,功能有重叠性,但是各有⾃⼰的特点,互相不可替代。

1、

语法概念上引⽤是⼀个变量的取别名不开空间,指针是存储⼀个变量地址,要开空间。但在汇编层面上,其实引用还是以指针的形式运行的

2、

引⽤在定义时必须初始化,指针建议初始化,但是语法上不是必须的。

3、

引⽤在初始化时引⽤⼀个对象后,就不能再引⽤其他对象;⽽指针可以在不断地改变指向对象。

4、

引⽤可以直接访问指向对象,指针需要解引⽤才是访问指向对象。

5、

sizeof中含义不同,引⽤结果为引⽤类型的⼤⼩,但指针始终是地址空间所占字节个数(32位平台下占4个字节,64位下是8byte)

6、

指针很容易出现空指针和野指针的问题,引⽤很少出现,引⽤使⽤起来相对更安全⼀些。

7、nullptr

在C语言中NULL其实是一个头文件为(stddef.h)

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

由代码可得C++中NULL可能被定义为0或者被定义为无类型(void*)的常量

void f(int x)
{cout << "f(int x)" << endl;
}void f(int* ptr)
{cout << "f(int* ptr)" << endl;
}int main()
{//f(NULL);   // 调用这个函数时原本要为f(int* ptr),但因为被定义为0,所以结果为f(int x),错误//f((void*)0); // 该函数调用会报错f(nullptr);return 0;
}

所以在C++11中引入了nullptr,它是一个特殊关键字,他可以转换成任意类型的指针类型,使用它可以避免类型转换的问题,因为它可以隐式转换为指针类型,而不会转换为整数类型

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

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

相关文章

selenium元素定位校验以及遇到的元素操作问题记录

页面元素定位方法及校验 使用比较多的是通过id、class和xpath来对元素进行定位。在定位前可以现在浏览器验证是否可以找到指定的元素。这样就不用每添加一个元素定位都运行代码来检查定位方式表达式是否正确。 使用XPATH定位 在浏览器F12&#xff0c;找到元素&#xff0c;在元…

网络安全之国际主流网络安全架构模型

目前&#xff0c;国际主流的网络安全架构模型主要有&#xff1a; ● 信息技术咨询公司Gartner的ASA&#xff08;Adaptive Security Architecture自适应安全架构&#xff09; ● 美国政府资助的非营利研究机构MITRE的ATT&CK&#xff08;Adversarial Tactics Techniques &…

CC工具箱使用指南:【CAD导出界址点Excel】

一、简介 群友定制工具。 面图层导出界址点Excel表之前已经做过好几个&#xff0c;这个工具则是将CAD导出Excel。 CAD数据如下&#xff1a; 工具将如上截图中的边界线导出界址点Excel&#xff0c;并记录下面内的文字。 二、工具参数介绍 点击【定制工具】组里的【CAD导出界…

如何在项目中用elementui实现分页器功能

1.在结构部分复制官网代码&#xff1a; <template> 标签: 这是 Vue 模板的根标签&#xff0c;包含所有的 HTML 元素和 Vue 组件。 <div> 标签: 这是一个普通的 HTML 元素&#xff0c;包裹了 el-pagination 组件。它没有特别的意义&#xff0c;只是为了确保 el-pagi…

Linux安装Nginx和Nginx基础配置

下载Nginx 方式一&#xff1a;通过官网下载后上传 通过官网下载安装包。下载地址https://nginx.org/en/download.html 这里选择稳定版的进行下载。 这里使用FinalShell终端工具操作&#xff0c;使用其他工具操作亦可。FinalShell工具下载地址&#xff1a;http://www.hostbuf…

Ubuntu20.04从零安装IsaacSim/IsaacLab

Ubuntu20.04从零安装IsaacSim/IsaacLab 电脑硬件配置&#xff1a;安装Isaac sim方案一&#xff1a;pip安装方案二&#xff1a;预构建二进制文件安装1、安装ominiverse2、在ominiverse中安装isaac sim&#xff0c;下载最新的4.2版本 安装Isaac Lab1、IsaacLab环境克隆2、创建con…

C++ STL知识点100问

1问&#xff1a;STL有哪几类&#xff0c;对其进行简单描述 答&#xff1a;STL 主要由适配器 allocator&#xff0c;容器 container&#xff0c;算法 algorithm,迭代器 iterator 和仿函数 functor5大类构成。 适配器allocator&#xff1a;STL 提供了三个容器适配器&#xff1a;…

基于Java Springboot宠物猫售卖管理系统

一、作品包含 源码数据库全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据库&#xff1a;…

python处理单元格语句去重

Python处理单元格内连续出现的重复词语 1. 环境配置 导入必要的库 import pandas as pd # 数据处理库 import re # 正则表达式库 import jieba # 中文分词库2. 处理字符串 检查输入有效性‌ &#xff1a;如果输入是 NaN、None 或非字符串类型&#xff0c;则直接返回输入。…

Linux—ln(link files)命令使用方法(How to create links on Linux)

Linux—ln&#xff08;link files&#xff09;命令使用方法 在 Linux 系统中工作时&#xff0c;需要在不同的目录中使用相同的文件时&#xff0c;不必在每个目录下都复制一份文件&#xff0c;这样不仅浪费磁盘空间&#xff0c;还会导致文件管理上的混乱。 ln(link files) 便是…

RecyclerView详解——(四)缓存复用机制

稍微看了下源码和部分文章&#xff0c;在此做个小小的总结 RecyclerView&#xff0c;意思为可回收的view&#xff0c;那么相对于listview&#xff0c;他的缓存复用肯定是一大优化。 具体而言&#xff0c;当一个列表项被移出屏幕后&#xff0c;RecyclerView并不会销毁其视图&a…

vulhub之log4j

Apache Log4j Server 反序列化命令执行漏洞(CVE-2017-5645) 漏洞简介 Apache Log4j是一个用于Java的日志记录库,其支持启动远程日志服务器。Apache Log4j 2.8.2之前的2.x版本中存在安全漏洞。攻击者可利用该漏洞执行任意代码。 Apache Log4j 在应用程序中添加日志记录最…

(附项目源码)Java开发语言,215 springboot 大学生爱心互助代购网站,计算机毕设程序开发+文案(LW+PPT)

摘 要 在网络信息的时代&#xff0c;众多的软件被开发出来&#xff0c;给用户带来了很大的选择余地&#xff0c;而且人们越来越追求更个性的需求。在这种时代背景下&#xff0c;企业只能以用户为导向&#xff0c;按品种分类规划&#xff0c;以产品的持续创新作为企业最重要的竞…

IDEA旗舰版编辑器器快速⼊门(笔记)

简介&#xff1a;javaweb开发必备软件之IDEA期间版介绍 DEA编辑器器版本介绍 官⽹网&#xff1a;https://www.jetbrains.com/地址&#xff1a;https://www.jetbrains.com/idea/download/#sectionmac DEA 分社区版(Community) 和 旗舰版(Ultimate)&#xff0c;我们做JavaWeb开…

【C++之STL】摸清 string 的模拟实现(上)

文章目录 1. 为什么要模拟实现&#xff1f;2. 基本框架搭建3. 构造函数3. 1 默认构造/from c_str3. 2 拷贝构造3. 2. 1 深浅拷贝 3. 3 fill3. 4 迭代器区间构造 4. 容量操作4. 1 size()和capacity()和empty()4. 2 clear()4. 3 resize()4. 4 reserve() 1. 为什么要模拟实现&…

Docker: ubuntu系统下Docker的安装

安装依赖 操作系统版本 Ubuntu Kinetic 22.10Ubuntu Jammy 24.04 (LTS)Ubuntu Jammy 22.04 (LTS)Ubuntu Focal 20.04 (LTS)Ubuntu Bionic 18.04 (LTS) CPU架构支持 ARMx86_64 查看我们的系统版本信息 uname -a通过该命令查得cpu架构是x86_64的&#xff1b; cat /etc/*re…

vue2+3 —— Day5/6

自定义指令 自定义指令 需求&#xff1a;当页面加载时&#xff0c;让元素获取焦点&#xff08;一进页面&#xff0c;输入框就获取焦点&#xff09; 常规操作&#xff1a;操作dom “dom元素.focus()” 获取dom元素还要用ref 和 $refs <input ref"inp" type&quo…

如何确保爬取的数据准确性和完整性?

在数据驱动的业务环境中&#xff0c;爬虫程序的准确性和完整性至关重要。本文将探讨如何使用Java编写爬虫程序&#xff0c;并确保其在爬取数据时的准确性和完整性。 1. 精确的HTML解析 确保数据准确性的第一步是精确地解析HTML。Jsoup是Java中常用的HTML解析库&#xff0c;它提…

关于Web Component

2024年8月14日 引言 Web Component 是一种用于构建可复用用户界面组件的技术&#xff0c;开发者可以创建自定义的 HTML 标签&#xff0c;并将其封装为包含逻辑和样式的独立组件&#xff0c;从而在任何 Web 应用中重复使用&#xff0c;并且可以做到无框架跨框架。 不同于 Vue…

【MySql】实验十六 综合练习:图书管理系统数据库结构

文章目录 创建图书管理系统数据库结构一、创建数据表1.1 book表1.2 reader表1.3 borrow表 二、插入示例数据2.1 向book表插入数据2.2 向reader表插入数据2.3 向borrow表插入数据 三、查询操作3.1 根据语义为借书表borrow的bno列和 rno列建立外键3.2 查询张小海编写的“数据库原…