C++入门

这一期时关于C++的内容,从基础开始,大家都加油鸭!!!

文章目录

  • 一.命名空间
    • [1.1 namespace的价值](#1.1 namespace的价值)
    • [1.2 namespace的定义](#1.2 namespace的定义)
    • [1.3 命名空间使用](#1.3 命名空间使用)
  • [二. C++输入和输出](#二. C++输入和输出)
  • [三. 缺省参数](#三. 缺省参数)
  • [四. 函数重载](#四. 函数重载)
  • [五. 引用](#五. 引用)
    • [5.1 引用的概念](#5.1 引用的概念)
    • [5.2 引用的特性](#5.2 引用的特性)
    • [5.3 引用的使用](#5.3 引用的使用)
    • [5.4 越界问题](#5.4 越界问题)
    • [5.5 const引用](#5.5 const引用)
      • [4. const引用的方便之处:](#4. const引用的方便之处:)
    • [5.6 ==引用和指针的区别==](#5.6 ==引用和指针的区别==)

一.命名空间

1.1 namespace的价值

在C++里也有很多的变量(对象),函数和类。如果(变量,函数和类)的名称全部在全局作用域中,会产生冲突(比如在一个大型项目中,两个程序员分别完成两个部分的内容,有两个名称相同的变量名称,到底使用哪一个呢?)

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

1.2 namespace的定义

  1. 定义命名空间:namespace 空间的名字,后面再是花括号{}。和函数有点类似。
  2. 同一个域不能用同一个变量名,不同域可以用同一个变量名。
  3. namespace本质是定义一个域
  4. C++中域有函数局部域,全局域,命名空间域,类域(4个)。域影响的是编译时语法查找⼀个变量/函数/类型出处(声明或定义)的逻辑[默认是在局部域main查找,之后会去全局域查找,不会主动去命名空间找],所以有了域隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑 ,还会影响变量的生命周期 ,命名空间域和类域不影响变量生命周期,它们只是利用域做了隔离(在main函数里还可以用命名空间hou里面的变量,hou::rand)。
cpp 复制代码
#include<stdio.h>
#include<stdlib.h>  //注意,在这个库里有rand函数,在没有说明的情况下调用的是全局域里的
namespace hou
{
	int Add(int left, int right)
	{
		return left + right;
	}

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

int main()
{
	//调用命名空间里的函数
	int a = hou::Add(1,2); 
	//原本是Add,现在是hou::Add(1,2)

	//调用命名空间里的结构体
	struct hou::Node bian;
	//原本是struct Node bian;  注意hou::的位置
}
  1. namespace只能定义在全局,不能在main函数或者什么局部域里面定义。namespace只是为了和全局的内容做隔离,而局部域和全局的内容天然就是隔离的。
  2. namespace可以嵌套定义
cpp 复制代码
namespace hou
{
	namespace rong
	{
		int rand = 10;
	}
	
	namespace ning
	{
		int rand = 90;
	}
}
int main()
{
	printf("%d\n", hou::ning::rand);
}
  1. 项目工程中多文件中定义的同名namespace会认为是一个namespace,不会冲突。
  2. C++标准库都放在一个叫std(standard)的命名空间中。

1.3 命名空间使用

编译查找一个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间里面去查找。所以我们要使用命名空间中定义的变量/函数,有三种方式:

  1. 指定命名空间访问(推荐推荐推荐)
cpp 复制代码
//比如   hou::rand
  1. using将命名空间中的全部成员展开(但不推荐这种方式,会有命名冲突的风险)
cpp 复制代码
using namespace hou;
//这样的话,找rand不仅会在全局域找,还会在hou里面找
  1. using将命名空间中某个成员展开(但不推荐这种方式,会有命名冲突的风险)
cpp 复制代码
using hou::rand;

二. C++输入和输出

  • iostream是 Input Output Stream 的缩写,是标准的输入、输出流库,定义了标准的输入、输出对象。
  • std::cin 是 istream 类的对象,它主要面向窄字符(narrow characters (of type char))的标准输入流。(c是字符的意思)【只有在内存当中才有整型,浮点型,字符,原反补,而在其他设备:如文件,网络,终端控制台等等只认识字符】
  • std::cout 是 ostream 类的对象,它主要面向窄字符的标准输出流
  • std::endl 是一个函数,流插入输出时,相当于插入一个换行字符加刷新缓冲区。(endl----->end line结束行)
  • <<是流插入 运算符(<< 这个全名是流插入操作符,作用就是向控制台打印),>>是流提取运算符。(C语言还用这两个运算符做位运算左移/右移)【可以自动识别变量类型,什么意思呢?就是不需要再写%d,%s之类的,<<可以自动识别】
  • cout/cin/endl等都属于C++标准库,C++标准库都放在一个叫std(standard)的命名空间中,所以要通过命名空间的使用方式去用他们。
cpp 复制代码
#include<iostream>
int main()
{
	std::cout << "hello world!";  //cout标准输出流

	//如果想换行的话
	std::cout << "hello world!"<<std::endl;  //C++推荐这个方式
	std::cout << "hello world!" << ' \n';    //可以连续的输出流插入,类型甚至可以不一样
		
}
  • 这里我们没有包含<stdio.h>,也可以使用printf和scanf,在包含iostream时间接包含了。vs系列编译器是这样的,其他编译器可能会报错。

三. 缺省参数

  1. "缺省参数"又叫做"默认参数",有参数,使用指定的参数;没有参数,使用缺省参数。(C语言没有缺省参数)

  2. 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。

  3. 缺省参数分为全缺省和半缺省参数。

    -全缺省:全部形参给缺省值(即形参一个都没有,都使用默认值)。

    -半缺省:传了部分形参,但还有一部分形参使用缺省值(默认值)。C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值。

cpp 复制代码
void function(int a=1, int b=2, int c=3)
{
	printf("%d %d %d\n", a, b, c);
}
int main()
{
	function();  //全缺省(全部形参使用缺省值)
	function(11);  //半缺省(没有传部分形参)
	               //function(,22,)这个是错误的,半缺省参数必须从右往左依次连续缺省
}
  1. 函数声明和定义分离时 ,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值。 (声明是在.h(即目录)里的那个(void function(ST* ps,int a = 10);),定义是在.cpp的那个void function(ST* ps,int a){}

四. 函数重载

C++支持在同一作用域中出现同名函数,但是要求这些同名函数的形参不同。(C语言不支持)

  1. 参数个数不同。
  2. 参数类型不同。
  3. 参数顺序不同。(本质还是参数类型不同)
  4. '返回值不同'不能作为重载条件,因为调用时也无法区分,不知道该调用哪一个。
cpp 复制代码
// 1、参数类型个数不同
void f()
{
  ///
}
void f(int a)
{
   ///
}
f();
f(12);
cpp 复制代码
// 2、参数类型不同
int Add(int left, int right)
{
   ///
}
double Add(double left, double right)
{
   
}
//调用时:
Add(10,20);
Add(1.1,2.2);
cpp 复制代码
void f(int a, char b)
{
  //
}
void f(char b, int a)
{
  
}
f(10,'m');
f('m',10);

错误:

cpp 复制代码
// f()但是调⽤时,会报错,存在歧义,编译器不知道调⽤谁
//语法上不存在错误,但调用时会有问题
void f1()
{
   /
}
void f1(int a = 10)
{
  //
}

f1(); //有可能是第一个,也有可能时第二个,使用缺省值

五. 引用

5.1 引用的概念

引用:给已经存在的变量重起一个别名 。(编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间

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

cpp 复制代码
int a = 10;
int& b = a;    //给a起一个别名b

区分typedef 和引用

typedef:给类型起别名

引用:给变量起别名

5.2 引用的特性

  1. 引用的对象必须是初始化过的。(引用在定义是必须初始化)
  2. 一个变量可以有多个引用。(可以有多个别名)
  3. 引用一旦引用一个实体,再不能引用其他实体。(专属别名)

5.3 引用的使用

引用的好处:

减少拷贝------>(1)提高效率;(2)改变引用对象(小号)的同时,改变被引用对象(本人)

引用--->没有开空间--->减少拷贝---->效率

  1. 引用传参:引用传参跟指针传参功能是类似的。
    以前想改变a,b的值,需要把a和b的地址传过去,通过地址改变它们的值。
    现在不需要这么麻烦,可以直接给a和b取个别名,将形参写成别名,改变别名即改变本人。

指针传参

引用传参

cpp 复制代码
void change(int& aa,int&bb)
{          //aa是a的别名,bb是b的别名
           //aa是引用对象,a是被引用的对象
	aa = 1;
	bb = 9;
}
int main()
{
	int a = 10;
	int b = 90;
	
	change(a,b);   //以a举例:a传递给形参int& aa的时候, 这个aa就是a的引用
	std::cout << a << " " << b;
}
  1. 引用返回值
    STTop()是一个返回值为int类型的函数,想让函数的返回值++,不能直接写STTop()++。

5.4 越界问题

越界访问不一定报错。

  1. 越界,不报错。【比如数组a里有10个元素,cout<<a[10];就是越界读】
  2. 越界,不一定报错。(越界写是以抽查的方式,越界的地方放一个值,比如-1,如果被改的话,就是越界写)【比如数组a里有10个元素,a[10]=33;就是越界写】

5.5 const引用

cpp 复制代码
const int a = 10;
int& ra = a;

1.大家注意,这个方式是不可以的哈。可以引用const对象,但是必须也用const引用。

cpp 复制代码
const int a = 10;
const int& ra = a;

2.const可以引用const对象,也可以引用普通对象。(对象的访问权限 在引用过程中可以缩小,但是不能放大。对象是const int代表着这个a值不能被修改,那么你的别名一定也没有修改的权限)

cpp 复制代码
//权限可以缩小
int b = 1;       //b可以被修改
const int& rb = b;  //b的别名rb,它的权限缩小了,不能被修改

//整个过程只影响rb的权限,不影响b的权限
cpp 复制代码
//权限不可以被放大
//这个代码是不可以的,pa(即a的地址)不能被修改
//pb(也想存储a的地址),怎么可以让它是int*类型可以被修改呢
const int a = 10;
const int* pa = &a;
int* pb = pa;  

const在*之前const int* pa=&a;,修饰的是变量的内容。在 * 之后int* const pa=&a;,修饰的是变量本身.

cpp 复制代码
//错误示范
int a = 10;
const int* pa = &a; //pa的内容(a的地址)不能被修改
int* pb = pa;   
//正确示范
int b = 99;
int* const pb = &b;  //pb不能被修改(而不是pa指代的内容不能改),即pa里面存的内容一定b的地址
int* pbb = pb;     //pb里放的内容和pa一样,但pb里的内容可以变
cpp 复制代码
int a = 9;
int& rb = a * 3;

首先先了解一下什么是临时对象?

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

a*3的值会先保存在临时对象里面,而C++规定临时对象具有常性(就像被const修饰一样),那么

cpp 复制代码
int a = 9;
//int& rb = a * 3;   
//表达式a*3被保存在临时变量里,被const修饰。而rb是int&,没有被const修饰。本质是权限变大的问题
//应该改成
const int& rb=a*3;
cpp 复制代码
double a = 12.34;
const int& ra = a;

4. const引用的方便之处:

可以引用普通对象,const对象,临时对象

cpp 复制代码
void func(const int& cc)
{
	//将参数写做const int&是很方便的,调用函数时,既可以是int(缩小权限)
	//又可以是const int&(权限没变)
	//还可以是表达式 或者 double
}
int main()
{
	int a = 0;
	func(a);
	const int b = 9;
	func(b);

	func(a * 3);

	double d = 2.2;
	func(d);

}

现在引用的都是比较小的参数,假如是4000多自己,传参的话需要临时拷贝,需要大量空间,这时引用就很厉害了。

5.6 引用和指针的区别

各有自己的特点,互相不可替代

  1. 引用是一个变量的取别名不开空间,指针是存储一个变量地址,要开空间
  2. 引用在定义时必须初始化,指针建议初始化,但是语法上不是必须的。
  3. 引用在初始化时引用一个对象后,就不能再引用其他对象;而指针可以在不断地改变指向对象。
  4. 引用可以直接访问指向对象,指针需要解引用才是访问指向对象。
  5. sizeof中含义不同,引用结果为引用类型的大小,但指针始终是地址空间(地址)所占字节个数(32位平台下占4个字节,64位下是8byte)
  6. 指针很容易出现空指针和野指针的问题,引用很少出现,引用使用起来相对更安全一些
相关推荐
爱吃生蚝的于勒1 小时前
C语言内存函数
c语言·开发语言·数据结构·c++·学习·算法
小白学大数据3 小时前
Python爬虫开发中的分析与方案制定
开发语言·c++·爬虫·python
versatile_zpc5 小时前
C++初阶:类和对象(上)
开发语言·c++
小鱼仙官5 小时前
MFC IDC_STATIC控件嵌入一个DIALOG界面
c++·mfc
神仙别闹5 小时前
基本MFC类框架的俄罗斯方块游戏
c++·游戏·mfc
娅娅梨6 小时前
C++ 错题本--not found for architecture x86_64 问题
开发语言·c++
兵哥工控6 小时前
MFC工控项目实例二十九主对话框调用子对话框设定参数值
c++·mfc
我爱工作&工作love我6 小时前
1435:【例题3】曲线 一本通 代替三分
c++·算法
娃娃丢没有坏心思7 小时前
C++20 概念与约束(2)—— 初识概念与约束
c语言·c++·现代c++
lexusv8ls600h7 小时前
探索 C++20:C++ 的新纪元
c++·c++20