【C++】C++入门知识(上)

news2024/11/18 18:43:21

 好久不见,本篇介绍一些C++的基础,没有特别的主题,话不多说,直接开始。

1.C++的第一个程序

C++中需要把定义文件代码后缀改为 .cpp 

我们在 test.cpp 中来看下面程序

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

相信大家再熟悉不过了,这是一个C语言的简单代码,我们运行代码发现也没问题

这是因为C++兼容C语言绝大多数的语法,所以C语言实现的hello world依旧可以运行,当然,C++也有自己的一套输入输出,严格来说C++版本的hello world应该像下面这样写

#include <iostream>
using namespace std;
int main()
{
	cout << "hello world" << endl;
	return 0;
}

啊?namespace  std是什么啊?cout啥意思啊?<< 这又是啥?......

相信大家初次看到C++的代码一定会有这些疑惑,不着急,我们一个一个来简单看看。

2.命名空间namespace

2.1 namespace的价值

namespace是我们接触的C++的第一个关键字

我们先看下面的程序,从程序现象分析namespace的价值

#include <stdio.h>
int rand = 10;
int main()
{
	printf("%d\n", rand);
	return 0;
}

此时,上面的程序可以正常运行,不会报错

但是我们如果加上#include <stdlib.h>呢?

#include <stdio.h>
#include <stdlib.h>
int rand = 10;
int main()
{
	printf("%d\n", rand);
	return 0;
}

程序就会报下面的错误,说rand重定义了

多加了个头文件程序为什么会重定义呢? 

C语言中有个东西叫命名冲突,在同一域内,不能定义同名的东西。没有包含 <stdlib.h> 时,全局只有一个rand变量,此时没有冲突,程序正常运行,但是,包含 <stdlib.h> 这个头文件后就有问题了,是因为rand是C语言库里的函数,头文件stdlib.h包含这个库函数,所以变量rand和库函数rand两个名字就冲突了

为了解决C语言中命名冲突的问题,C++设计了namespace,命名空间

2.2 namespace的定义

定义命名空间,需要使用namespace关键字,后面跟命名空间的名字,然后接一对{},{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等

2.2.1 namespace定义变量 

以上面的rand为例,定义一个命名空间,命名空间的名字随便起嗷

namespace lyj
{
	int rand = 10;
}
#include <stdio.h>
#include <stdlib.h>
namespace lyj
{
	int rand = 10;
}
int main()
{
	printf("%d\n", rand);
	return 0;
}

namespace本质是定义出一个域,这个域跟全局域各自独立,不同的域可以定义同名变量

此时再看我们的程序,运行没有报错,变量rand和函数rand已经不在同一个域内了,就不会冲突

虽然程序没有报错,但是报了如下警告

报警告是因为此时这里的rand访问的是全局的函数,并不是命名空间里的变量rand,解除警告可以把%d改成%p,就是打印函数rand的地址。

那我们要访问namespace里的rand怎么访问?

2.2.2 域作用限定符::

我们要知道一个运算符 :: 两个冒号,叫做域作用限定符,先看下面的代码

#include <stdio.h>
int a = 20;
int main()
{
	int a = 10;
	printf("%d\n", a);
	return 0;
}

根据局部优先的规则,我们打印出来的应该是10,而不是20

 

我们用了::这个运算符后,并且::的左边什么也不给(左边留空格只是为了格式好看),就默认去全局查找,如下

	printf("%d\n", ::a);

 那么打印出来的就是20

理解了之后我们回过头来看上面的rand,想要在命名空间查找,::左边就是命名空间的名字,如下

#include <stdio.h>
#include <stdlib.h>
namespace lyj
{
	int rand = 10;
}
int main()
{
	printf("%d\n", lyj::rand);
	return 0;
}

此时就能解决名字冲突的问题,想访问哪个域就访问哪个域

 

C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找一个变量/函数/类型出处(声明或定义)的逻辑,所以有了隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找的逻辑,还会影响变量的生命周期,命名空间域和类域不影响变量的生命周期

2.2.3 namespace定义函数和类型

这里简单举几个例子,比如下面的命名空间,定义了一个简单的函数和结构体

namespace lyj
{
	int add(int a, int b)
	{
		return a + b;
	}
	struct node
	{
		struct node* next;
		int val;
	};
}

函数直接指定就行了

int main()
{
	printf("%d\n", lyj::add(1, 1));
	return 0;
}

 

定义结构体的话就稍微不同一些 ,命名空间的名字放在struct的后面,结构体名字的前面

int main()
{
	struct lyj::node p1;

	return 0;
}

2.2.4 namespace的嵌套定义和合并

namespace只能定义在全局,当然它还可以嵌套定义

namespace group
{
	namespace zhangsan
	{
		int num = 1;
		int add(int a, int b)
		{
			return a + b;
		}
	}
	
	namespace lisi
	{
		int num = 2;
	    struct node
		{
			struct node* next;
			int val;
		};
	}
}

 比如上面这个例子,就是namespace的嵌套定义。如果我们要分别打印group下面张三的num和李四的num,像下面这样就行了

    printf("%d\n", group::zhangsan::num);
	printf("%d\n", group::lisi::num);

如果代码复杂一点,有几个头文件和源文件,那此时怎么运用命名空间呢?

其实,不同文件的命名空间,名字相同会自动合并 。当然,这个合并并不是真的合并在一起,只是逻辑上的合并,名字相同的namespace会认为是一个namespace。举个简单例子

Func.h文件中有下面的函数声明

namespace func1
{
	int Add(int a, int b);
	int Sub(int a, int b);
}

namespace func2
{
	int Mul(int a, int b);
	float Div(int a, int b);
}

Func.cpp文件中有下面的函数

#include "Func.h"
namespace func1
{
	int Add(int a, int b)
	{
		return a + b;
	}

	int Sub(int a, int b)
	{
		return a - b;
	}
}
namespace func2
{
	int Mul(int a, int b)
	{
		return a * b;
	}
	float Div(int a, int b)
	{
		return (float)a / b;
	}
}

虽然他们不在同一个文件,但是namespace func1中的内容和namespace func2中的内容都会被分别合并

2.3 C++中 std命名空间

2.3.1 关键字using

我们看下面的例子

namespace lyj
{
	int a = 1;
	int b = 2;
}

想要打印namespace里的a和b,就要像下面这样用::去一个个指定

    printf("%d\n", lyj::a);
    printf("%d\ ", lyj::b);

如果namespace里我们需要用的东西很多,像这样一个个指定真的太麻烦了,那么直接把整个namespace展开可以吗?可以。展开namespace就要用到关键字using。

    using namespace lyj;

加上这句话之后,就可以直接使用namespace里的东西

namespace lyj
{
	int a = 1;
	int b = 2;
}
using namespace lyj;
int main()
{
	printf("%d\n", a);
	printf("%d\n", b);
	return 0;
}

 

但是,展开命名空间中所有成员,在实战项目中不推荐,冲突风险很大

假设我在程序中用a用的非常多,不推荐展开全部,一次次展开又太麻烦了,怎么办?

using还可以局部展开。比如说我就展开a。

    using lyj::a;

 使用时,a就不需要用::去指定,可以直接使用,b没展开就要用::指定

2.3.2 std命名空间

C++标准库都放在一个叫std(standard)的命名空间中。

using namespace std;

这句话就是把C++标准库都展开。在日常练习中可以展开,不会有什么风险。

3.C++的输入和输出

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

C++的输入输出需要包含这个头文件,就相当于C语言中使用printf我们需要包含<stdio.h>这个头文件。那为什么iostream没有加.h呢?C++标准库版本问题,新版本是不需要加.h的,如果加了.h,证明那个编译器应该是特别老的编译器(比如vc6.0)。

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

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

std::endl 是一个函数(endl是endline的缩写),流插入输出时,相当于插入一个换行字符加刷新缓冲区(目前简单理解为换行符,其实这个函数很复杂)。

这里cin、cout中的c就是窄字符的意思,后面会学宽字符,目前我们遇到的都是窄字符。 

当我们在程序中展开了std,也就是using namespace std; 使用cin, cout, endl时就不需要加std::了,不过展开了std又加上了std:: 程序也不会报错,但有点多此一举了。

<<是流插入运算符,>>是流提取运算符。 

 C语言中用 << 和 >> 作为位运算符,<<是左移运算符,>>是右移运算符。

<<和>>是二元操作符,只能有两个操作数!

到现在,我们可以简单抽象地理解下面这句话了,就是把hello world 和endl 流向cout,而cout就是插入到终端或者控制台,其中endl简单来说就是换行符。

	cout << "hello world" << endl;

 C++输入、输出可以自动识别变量的类型

C语言中的printf和scanf需要手动指定格式,比如输入一个int a ,输出一个float b = 3.14

	int a;
	float b = 3.14;
	scanf("%d", &a);
	printf("%f", b);

而C++中就不需要指定格式,比如下面的cout输出

    int a = 1;
    float b = 3.14;
    char c = 'x';
    cout << a << " " << b << " " << c << endl;

 

再来看看cin输入,也是不需要指定类型的

	int y, z;
	cin >> y;
	cin >> z;
	cout << y << endl << z << '\n';

也可以cin >> y >> z;

 

类型不同也可以。 

还有一点,

在C语言中想要确定小数点的精度,像下面这样就行,

	double d = 2.22222222;
	printf("%.2lf\n", d);

在C++中小数精度是默认小数点后5位

在C++中可以控制小数点精度吗?可以但是比较复杂。所以我们需要在C++中确定精度的话直接用C语言的printf就行了,反正C++兼容C语言。

由于兼容和缓冲区等复杂原因,C++的cin和cout的IO效率有时候比较低,可以与scanf和printf混着用,在io需求比较高的地方,比如大量输入输出竞赛中,也可以加上下面的三句代码,提高C++IO效率。

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

 

本小篇就到这里,拜拜~

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

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

相关文章

Linux文件与相关函数的知识点3

main函数参数 int main(int argc,char *argv[]) { return 0; } C语言规定了main函数的参数只能有两个&#xff0c;一个是argc,一个是argv并且&#xff0c;argc只能是整数&#xff0c;第二个必须是指向字符 串的指针数组。 argc: 参数表示命令行中参数的个数&#xff0…

【建议收藏】CTF网络安全夺旗赛刷题指南(非常详细)零基础入门到精通,收藏这一篇就够了

在数字化浪潮汹涌澎湃的今天&#xff0c;网络安全已成为国家、企业和个人无法忽视的重要议题。为了挖掘和培养网络安全人才&#xff0c;一场场紧张刺激、充满智慧的CTF&#xff08;Capture The Flag&#xff09;安全竞赛应运而生。 一、CTF安全竞赛简介 CTF安全竞赛&#xff0c…

鸿蒙仓颉语言之【安全密码库crypto4cj】功能示例

功能示例 MD5使用样例 from crypto4cj import md5cj.*main() { var md: Array<UInt8> Array<UInt8>(16, item: 0)var result: String String(Array<Char>(33, item: 0))var str: String "helloworld"var ret md5(str.toUtf8Array(), md)r…

lua 游戏架构 之 游戏 AI (六)ai_auto_skill

定义一个为ai_auto_skill的类&#xff0c;继承自ai_base类。ai_auto_skill类的目的是在AI自动战斗模式下&#xff0c;根据配置和条件自动选择并使用技能。 lua 游戏架构 之 游戏 AI &#xff08;一&#xff09;ai_base-CSDN博客文章浏览阅读379次。定义了一套接口和属性&#…

ASCII码图片

在许多计算机语言中&#xff0c;比较字母、字符串大小时&#xff0c;都会运用到ASCII码。而这是很多创客容易遗忘的&#xff0c;今天发给大家ASCII码大全图片&#xff0c;记得收藏

Redis是多线程还是单线程?

文章目录 1、用户态和内核态2、阻塞IO3、非阻塞IO4、IO多路复用4.1 select4.2 poll4.3 epoll4.4 epoll中的ET和LT4.5 epoll的服务端流程 5、信号驱动6、异步IO7、对比8、Redis是单线程的吗&#xff1f;9、单线程多线程网络模型变更 1、用户态和内核态 1、ubuntu和Centos 都是Li…

Golang 知识结构图

总结Go的入门知识结构&#xff0c;如下图所示&#xff1a;

(史上最全的)Spring6框架学习教程

一、什么是Spring 1.javaWeb框架发展史 1、ServletJSPJavaBean(跳转页面、业务逻辑判断、数据库查询) 2、MVC三层架构(M Model pojo(User)V-view(USP)C-(controller-servlet)) (web-跳转页面service-业务逻辑判断 new UserService0;dao-数据库查询 new UserDao(); ) 3、使用…

【C++】—— 类和对象(一)

【C】—— 类和对象&#xff08;一&#xff09; 1、类的定义1.1、类定义1.1.1、类定义格式1.1.2、成员变量的标识1.1.3、C 中的 s t r u c t struct struct1.1.4、C 中的内联函数1.1.5、总结 1.2、访问限定符1.3、类域 2、实例化2.1、实例化的概念2.2、对象大小2.2.1、对象的大…

黑神话悟空游戏什么时候上线能玩 黑神话悟空是哪个公司 苹果电脑能玩黑神话悟空吗

《黑神话&#xff1a;悟空》是一款以中国神话为背景的动作角色扮演游戏。故事取材于中国古典小说“四大名著”之一的《西游记》。 你将扮演一位“天命人”&#xff0c;为了探寻昔日传说的真相&#xff0c;踏上一条充满危险与惊奇的西游之路。 一、《黑神话&#xff1a;悟空》什…

【Linux系统】线程的互斥

互斥 互斥概念 多个线程能够看到的资源称为共享资源&#xff0c;那我们需要对这种资源进行保护&#xff0c;需要用到互斥&#xff01;&#xff01;&#xff01; 见一见多线程访问的问题 --- 抢票问题 int tickets 1000;void route(const std::string& name) {while(tr…

Docker容器的数据管理

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 我们在使用Docker的过程中&#xff0c;往往需要能查看容器内应用产生的数据&#xff0c;或者需要把容器内的数据进行备份&#x…

python学习笔记——数字

一、数字概述 1.Python 数字数据类型用于存储数值。 数据类型是不允许改变的&#xff0c;这就意味着如果改变数字数据类型的值&#xff0c;将重新分配内存空间。 2.可以使用del语句删除一些数字对象的引用。 del var1[,var2[,var3[....,varN]]]3.可以通过使用del语句删除单个或…

【python014】Python爬取并解析潮汐天气简报-潮历数据

1.欢迎点赞、关注、批评、指正&#xff0c;互三走起来&#xff0c;小手动起来&#xff01; 【python014】Python爬取并解析潮汐天气简报-潮历数据&#xff0c;源代码下载【python014】Python爬取并解析潮汐天气简报-潮历数据&#xff0c;源代码下载【python014】Python爬取并解…

Aria2 任意文件写入漏洞

目录 Aria2介绍漏洞描述漏洞复现 Aria2介绍 Aria2是一个在命令行下运行&#xff0c;多协议&#xff0c;多来源下载工具&#xff08;HTTP / HTTPS&#xff0c;FTP&#xff0c;BitTorrent&#xff0c;Metalink&#xff09;&#xff0c;内建XML-RPC用户界面。Aria提供RPC服务器&a…

2.9.GoogLeNet

GoogLeNet ​ 主要解决了什么样大小的卷积核是最合适的&#xff1a;有时使用不同大小的卷积核组合是有利的 1.Inception块 ​ Inception块由四条并行路径组成。 前三条路径使用窗口大小为11、33和55的卷积层&#xff0c;从不同空间大小中提取信息。 ​ 中间的两条路径在输入…

任务管理无忧:2024年最佳7款待办事项管理软件

本文将分享2024年值得关注的7大优质待办事项管理软件&#xff1a;PingCode、Worktile、滴答清单、时光序、好用便签、Todoist、ClickUp。 在寻找完美的待办事项管理工具时&#xff0c;你是否感觉到选择众多却难以决断&#xff1f;无论是保持日程有序&#xff0c;还是优化团队协…

Linux基本用法(上)

1.计算机主要由 硬件和软件 组成 2.操作系统是什么 ? 有什么作用&#xff1f; 操作系统是软件的一类 主要作用是协助用户调度硬件工作&#xff0c;充当用户和计算机之间的桥梁 3.常见的操作系统有哪些? PC端: Windows&#xff0c;Linux,MacOS 移动端: Android&#xff…

UART 通信协议

文章目录 一 简介二 电平标准三 引脚定义四 数据格式五 波特率 一 简介 ​ UART (Universal Asynchronous Receiver/Transmitter)&#xff0c;通用异步收发器&#xff0c;是一种串行、异步、全双工通信协议。 串行&#xff1a;利用一条传输线&#xff0c;将数据一位一位地传送…

YOLOv8改进 | 主干网络 | ⭐重写星辰Rewrite the Stars⭐【CVPR2024】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录 &#xff1a;《YOLOv8改进有效…