在这里插入图片描述
前言:有过C语言学习的基础,C++入门很简单的,将用两篇来写完C++入门基础。


一.C++的第一个程序

C++兼容C语言绝大多数的语法,所以C语言实现的hello world依旧可以运行,C++中需要把定义文件代码后缀改为.cpp,vs编译器看到是.cpp就会调用C++编译器编译,linux下要用g++编译,不再是gcc。

当然C++有一套自己的输入输出,严格说C++版本的hello world应该是这样写的:

int main()
{
	cout << "hello world\n" << endl;

	return 0;
}

二.命名空间

2.1 namespace的价值

在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
c语言项目类似下面程序这样的命名冲突是普遍存在的问题,C++引入namespace就是为了更好的解决这样的问题。

我们来看一个问题:

在这里插入图片描述

该程序如果我们不加stdlib.h头文件,不会报错,但我们加上的话就会报错。

2.2 namespace的定义

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

•namespace本质是定义出一个域,这个域跟全局域各自独立,不同的域可以定义同名变量,所以下面的rand不在冲突了。

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

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

•项目工程中多文件中定义的同名namespace会认为是一个namespace,不会冲突。

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

下面都是对概念用相关例子来说明。

来解决我们上面代码出现的报错。
在这里插入图片描述
就算这时候库里面也有Add,rand和Node,也不会发生冲突,本质他们不是在同一个域里面的。

一般函数里面定义的那些叫局部域,还有我们写一个循环里面定义的又是一个更小的局部域。函数外面的都叫全局域,变量查找在域中默认的规则:没有指定的情况下,先在局部域查找,再在全局域查找。

比如:

在这里插入图片描述

当用到rand的时候,编译器去查找,先在局部域查找,没有,然后再去全局域查找,但全局有两个rand,一个是变量,一个是函数,所以发生冲突。

当我们把rand用命名空间封装起来,还是同样的查找规则,最后在头文件stdlib.h中找到,编译链接的阶段会预处理,将头文件的内容展开,打印的结果应该是函数地址。

查找默认规则:先在局部域查找,再到全局域查找,不会到命名空间域查找。

如果我们想要用命名空间里面的变量该怎么用呢?

2.3 命名空间使用

编译查找一个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间里面去查找。所以下面程序会编译报错。所以我们要使用命名空间中定义的变量/函数,有三种方式:
· 指定命名空间访问,项目中推荐这种方式。
· using将命名空间中某个成员展开,项目中经常访问的不存在冲突的成员推荐这种方式。
· 展开命名空间中全部成员,项目不推荐,冲突风险很大,日常小练习程序为了方便推荐使用。

在这里插入图片描述
::这是一个新的运算符,这个运算符叫做域作用限定符。这个时候我们指定了,所以直接会去该命名空间域中去查找。

嵌套定义命名空间的使⽤
在这里插入图片描述
在这里插入图片描述
使用结构体,因为命名空间封装的是命名的名字,所以我们应该这样写:
在这里插入图片描述

还有一点是:多个文件使用同一个命名空间来封装,都会合并在一起,但是要保证如果栈和队列文件合并一起的函数的命名不会发生冲突。
在这里插入图片描述


三.C++输入&输出

• 是 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)的命名空间中,所以要通过命名空间的使用方式去用他们。

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

•一般日常练习中我们可以using namespace std,实际项目开发中不建议using namespace std。· 这里我们没有包含<stdio.h>,也可以使用printf和scanf,在包含<iostream>间接包含了。vs系列编译器是这样的,其他编译器可能会报错。

在这里插入图片描述
如果打竞赛用c++写,极端情况下,需要大量的输入输出过不去的话,加上以下三段代码:

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

本质:关掉c++和c同步问题,因为c++兼容c,提高效率。


四.缺省参数

•缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参,缺省参数分为全缺省和半缺省参数。(有些地方把缺省参数也叫默认参数)

在这里插入图片描述

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

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

在这里插入图片描述

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

// Stack.h

#include <iostream>

#include <assert.h>

using namespace std;

typedef int STDataType;

typedef struct Stack

{
 STDataType* a;
 int top;
 int capacity;
}ST;

void STInit(ST* ps, int n = 4);

// Stack.cpp

#include"Stack.h"

// 缺省参数不能声明和定义同时给 

void STInit(ST* ps, int n)
{
 assert(ps && n > 0);
 ps->a = (STDataType*)malloc(n * sizeof(STDataType));
 ps->top = 0;
 ps->capacity = n;
}

// test.cpp

#include"Stack.h"

int main()
{
 ST s1;
 STInit(&s1);
 // 确定知道要插⼊1000个数据,初始化时⼀把开好,避免扩容 
 ST s2;
 STInit(&s2, 1000);
 return 0;
}


当我们用栈插入的时候,如果知道了需要用多少空间,可以通过用缺省参数,来减少频繁扩容,插入时没有扩容,提高效率,如果不知道插入多少数据,给一个适中的缺省值,不够继续扩。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐