C++入门(上)

嘿嘿,家人们,从今天开始我们将进入C++的学习,在C++这块呢,博主不讲和C语言重合的语法,所以如果对C语言不是很熟悉的话, 可以去看看博主C语言滴博客,好啦,废话不多讲,接下来我们开始进入C++的学习!

1:什么是C++

C语言是一门面向过程的语言,是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机,20世纪80年代,计算机界提出了OOP(object oriented programming:面向对象)思想,支持面向对象的程序设计语言应运而生。
1982年,Bjarne Stroustrup博士在C语言的基础上引入并扩充了面向对象的概念,发明了一种的新的程序语言。为了表达该语言与C语言的渊源关系,命名为C++。因此:C++是基于C语言而产生的,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计。

2.C++的发展史

1979年,贝尔实验室的本贾尼等人试图分析unix内核的时候,试图将内核模块化,于是在C语言的基础上进行扩展,增加了类的机制,完成了一个可以运行的预处理程序,称为C with classes。
编程语言的发展史和我们日常打游戏时打怪升级一样,也是不断地逐步递进,由浅入深的过程。下面是C++的历史版本.

在这里插入图片描述

C++还在不断地向后发展,博主在这里主要是以C++98与C++11为主,因为公司主流使用的还是C++98与C++11,将C++98与C++11掌握好以后,随着对C++的理解不断加深,uu们有时间可以去琢磨更新的特性。

3:C++关键字(C++98)

简单了解了C++这门面向对象的编程语言后,接下来,我们来看一下C++的关键字,C++总计有63个关键字,C语言总共32个关键字.
PS:下面只是让uu们看一下C++有多少关键字,不对关键字进行具体的讲解,有些关键字在C语言阶段就已经见过了,对于那些没有见过的,等后面博主会给uu们进行细讲的.

在这里插入图片描述

4:命名空间

在讲命名空间以前,我们首先来看下面这段代码。
#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int x = 5;
int main()
{
    int x = 25;
    printf("%d\n", x);
    //访问的是全局变量x
    printf("%d\n",::x);
    return 0;
}

这段代码我定义了两个变量x,一个是全局变量x,一个是局部变量x,C语言阶段博主讲过,如果全局变量和局部变量的变量名冲突了,那么在访问的时候是优先访问局部变量,但是这个时候如果非要访问这个全局变量x那应该怎么办呢?在C++中我们则可以使用域作用限定符::来访问这个全局变量x.域作用限定符在不指定域的情况下默认为全局作用域

在这里插入图片描述

4.1:命名空间的概念

在C/C++中,变量、函数和之后博主要讲到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。

我们首先来看下面这段代码。
#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int rand = 5;
int main()
{
    printf("%d", rand);
    return 0;
}

在这里插入图片描述

这段代码的报错提示是说rand以前定义的是函数,我们知道在C语言阶段,rand是一个库函数,需要包含头文件<stdlib.h>,在C++中我们为了避免命名冲突和名字污染,则提出了命名空间的概念.

4.2:命名空间的定义

定义命名空间,需要使用到关键字namespace关键字,后面跟命名空间的名字,然后接一对{},{}中即为命名空间的成员.

#include <stdio.h>
namespace area1
{
	int rand = 25;
}

namespace area2
{
	int rand = 30;
	int Add(int value1,int value2)
	{
		return value1 + value2;
	}
}

int main()
{
	int result = area2::Add(25, 30);
	printf("%d\n", area1::rand);
	printf("%d\n", area2::rand);
	printf("%d\n", result);
	return 0;
}

在这里插入图片描述

一个命名空间就相当于定义了一个新的作用域,命名空间中的所有内容都局限于此命名空间中.在命名空间中我们可以定义变量/函数/类型等,如果说我们访问某个命名空间里面的成员,则需要使用::(域作用限定符)来指定域,然后跟上变量名来进行访问.此时我们再使用变量rand去命名时发现编译器不会报错了,因为将其锁定在了一个新的作用域,并且使用域作用限定符来指定域去进行访问了.

namespace area1
{
	struct Node
	{
		struct Node* next;
		int value;
	};
}
int main()
{
	//命名空间中结构体的使用
	struct area1::Node* Head;
	return 0;
}

PS:使用命名空间中的结构体跟使用命名空间中的变量与函数是有些不一样滴,这里uu们要稍微注意下。

除此之外,在同一个工程中允许存在多个相同名称的命名空间,编译器最后会将其合成在同一个命名空间中,我们看下面这段代码.

#pragma once
namespace area1
{
	int Add(int value1, int value2)
	{
		return value1 + value2;
	}
}
#include "List.h"
namespace area1
{
	struct Node
	{
		struct Node* next;
		int value;
	};
	int Add(int value3, int value4)
	{
		return value4 + value3;
	}
}
int main()
{
	//命名空间中结构体的使用
	struct area1::Node* Head;
	return 0;
}

在这里插入图片描述

博主在头文件List.h与test.cpp这个文件中都定义了Add函数并且命名空间使用了同一个名字,并且在test.cpp这个文件中包含了头文件List.h,这个时候我们运行这段代码会发现编译器给我们报错了,这是因为编译器将两个同样名称的命名空间合并在了一起,这个时候就出现了两个一模一样的函数,我们在C语言阶段讲过,一个工程中是不能出现两个一模一样的函数滴,所以编译器这里给我们进行了报错.

4.3:命名空间的使用

在命名空间中,我们可以定义变量、函数、结构体、类型等等,那么我们该如何去使用呢?以下三种方法可以帮助我们去使用命名空间里头的数据.

4.3.1加命名空间的名称以及域作用限定符

第一种方式呢就是通过域作用限定符+命名空间的名称来指定访问此命名空间中的数据.我们看下面这段代码.

#include <stdio.h>
namespace area1
{
	int value1 = 1;
	struct Node
	{
		struct Node* next;
		int value;
	};
	int Add(int value3, int value4)
	{
		return value4 + value3;
	}
}
int main()
{
	//命名空间中结构体的使用
	struct area1::Node* Head;
	area1::value1 = 25;
	printf("%d\n", area1::value1);
	return 0;
}

在这里插入图片描述

通过域作用限定符::,左边跟上命名空间的名称,右边则跟上该命名空间中的变量名来进行访问.

4.3.2:使用using将命名空间中某个成员引入

第二种方式则是使用using关键字将命名空间中的某个成员进行引入,这个时候我们就能直接进行访问了,不需要指定域了,我们看下面这段代码.

#include <stdio.h>
namespace area1
{
	int value1 = 1;
	struct Node
	{
		struct Node* next;
		int value;
	};
	int Add(int value3, int value4)
	{
		return value4 + value3;
	}
}
//使用using关键字将命名空间area中的进行进入
using area1::value1;
int main()
{
	//命名空间中结构体的使用
	struct area1::Node* Head;
	area1::value1 = 30;
	printf("%d\n", area1::value1);
	printf("%d\n",value1);
	return 0;
}

在这里插入图片描述

上面的代码中,当使用using关键字将命名空间area中的变量value1引入了以后,这个时候我们再去访问,就不需要指定域啦,可以直接进行访问.

4.3.3:使用using namespace +命名空间名称展开命名空间

第三种方式则通过使用using namespace + 命名空间名称展开命名空间来引入命名空间中的数据.

#pragma once

namespace QNodearea
{
	struct QNode
	{
		struct QNode* Node;
		int value;
	};
	int value = 30;
}
#pragma once
namespace Listarea
{
	struct List
	{
		struct List* Node;
		int value;
	};
	int value = 25;
}
代码1
#include <stdio.h>
#include "List.h"
//展开命名空间,拿到使用权限
using namespace Listarea;
int main()
{
	struct List* Node1;
	printf("%d", value);
	return 0;
}

在这里插入图片描述

在上述代码中,通过使用using namespace + 命名空间的名称展开命名空间,此时我们就能直接访问此命名空间中的数据了.

我们再来看下面这段代码

代码2
#include <stdio.h>
#include "List.h"
#include "QNode.h"
//展开命名空间,拿到使用权限
using namespace Listarea;
using namespace QNodearea;
int main()
{
	struct List* Node1;
	value;
	return 0;
}

此时我将命名空间Listarea,与QNodearea都进行了展开,此时我们再去使用value这个变量,看看会发生什么事?

在这里插入图片描述

很明显,此时编译器发生了报错,说不确定此value是Listarea中还是QNodearea中的,这个时候我们如果通过域作用限定符指定了域来进行访问的话,还会不会报错呢?

在这里插入图片描述

我们可以看到当我们指定了域以后此时编译器不发生报错,那这是为什么呢?原因在于编译器的搜索原则遵循以下规则:
不指定域:(1):先去当前的局部作用域搜索 (2):全局作用域搜索
指定域:若指定了域、就会直接去域里面进行搜索.
这也就是为什么当我们展开了两个命名空间,此时再去访问value那个变量会发生报错.

5:C++输入与输出

在C语言中有输入scanf与输出printf,在C++中同样也有滴哦!那么接下来我们来看看C++中的输入与输出.

代码1

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

在这里插入图片描述

这段代码就是C++版本的hello world,uu们可能对此有些小疑惑,我们一步步地来看.
1:使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件
2:std是C++标准库的命名空间名,C++标准库的定义实现都放到这个命名空间中.
3:cout和cin全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在< iostream >头文件中.
4:
<<是流插入操作符,>>是流提取运算符

代码2

#include <iostream>
using namespace std;
int main()
{
	int a;
	double b;
	char c;

	cin >> a;
	cin >> b >> c;

	cout << "a = " << a <<endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
	return 0;
}

在这里插入图片描述

这段代码就是C++滴输入方式。
1:使用C++输入输出更方便相较于C语言,不需要像printf/scanf输入输出时那样子手动控制格式,C++的输入输出可以自动识别变量类型。
PS:关于cout和cin还有很多复杂的用法,例如控制浮点数输出精度,控制整形输出格式等等,由于C++兼容C语言的用法,这些用法用得不是很多,因此博主在这里就不细讲啦.

6:缺省参数

6.1:缺省参数概念

缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参.

#include <iostream>
using namespace std;
//a为缺省参数
void Function(int a = 35)
{
	cout << a << endl;
}

int main()
{
	Function();
	Function(20);
	return 0;
}

在这里插入图片描述

在上述代码中,我调用了两次Function函数,第一次调用没有进行传参,第二次调用进行了传参,由于我第一次调用未进行传参,因此在输出变量a时使用了a的缺省值,第二次调用进行了实参的传递,因此使用指定实参.

6.2:缺省参数分类

了解了缺省参数的概念后,接下来博主将详细介绍缺省参数的分类.

6.2.1:全缺省参数

#include <iostream>
using namespace std;
//a为缺省参数
void Function(int a = 35,int b = 25,int c = 35)
{
	cout <<"a = " << a << endl;
	cout <<"b = " << b << endl;
	cout <<"c = " << c << endl;
}

int main()
{
	Function();
	cout << endl;
	Function(20,40);
	return 0;
}

在这里插入图片描述
在这里插入图片描述

在上述代码中,博主给每一个形参都赋予了缺省值,当形参全部都被赋予了缺省值,这时就是全缺省参数.并且在调用时,第一次调用未进行传参,因此形式参数使用的是缺省值,第二次调用只进行了部分传参,传参时,从左往右进行匹配,因此对于传递了实参的参数,则使用指定的实参,未传递实参的参数,则使用缺省值.
PS:传参时,不可跳跃传递哦!

6.2.2:半缺省参数

#include <iostream>
using namespace std;
void Function(int a,int b = 25,int c = 35)
{
	cout <<"a = " << a << endl;
	cout <<"b = " << b << endl;
	cout <<"c = " << c << endl;
}

int main()
{
	Function(20);
	cout << endl;
	Function(20,30);
	return 0;
}

在这里插入图片描述
在这里插入图片描述

在上述代码中,只对部分参数使用了缺省值,因此被称为半缺省参数,半缺省参数要遵从一个规则即:**必须从右往左依次来给出,不能够间隔着给.**除此之外缺省参数还有以下几个注意点.

  1. 缺省参数不能函数声明和定义中同时出现如果声明和定义位置同时出现缺省参数,那么编译器就无法确定到底该用哪个缺省值.
    在这里插入图片描述

上面的图片中,声明和定义都出现了缺省值,此时程序运行时会发生报错,因为编译器无法确定该使用哪个缺省值.二者非要指定的话,只能在声明中出现,而不是在定义中出现.

2.缺省值必须是常量或者全局变量.
3.C语言不支持缺省参数.

7:函数重载

在自然语言中,一个词有多重含义,人们可以通过上下文来判断该词的真实含义,即该词被重载了,那么在这种场景下,我们来了解函数重载.

7.1:函数重载概念

函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数或类型或类型顺序)不同,常用来处理实现功能类似数据类型不同的问题.

7.2:函数重载的分类

7.2.1:参数类型不同

#include <iostream>
using namespace std;
int Function(int value1,int value2)
{
	cout << "int Add(int value1,int value2)" << endl;
	return value1 + value2;
}

double Function(double value1,double value2)
{
	cout << "double Add(doublue value1,double value2)" << endl;
	return value1 + value2;
}

int main()
{
	int Iresult = Function(2, 5);
	double Dresult = Function(2.5, 9.52);
	cout << Iresult << endl;
	cout << Dresult << endl;
	return 0;
}

在这里插入图片描述

上述代码中定义了两个一模一样的函数名,但是这两个函数的形参的参数类型不同,因此构成了函数重载.

7.2.2:参数的个数不同

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

//2.参数的个数不同
void Func()
{
    cout << "Func()" << endl;
}

void Func(int a)
{
    cout <<"Func(int a) " << a << endl;
}

int main()
{
    Func();
    Func(5);
    return 0;
}

在这里插入图片描述

这段代码也同样定义两个相同的函数名,但是这两个函数的参数的个数不同,因此也构成了函数重载.

7.2.3:参数的顺序不同

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

void Function(int value1,char str1)
{
    cout << value1 << " " << str1 << endl;
}

void Function(char str1,int value1)
{
    cout << str1 << " " << value1 << endl;
}

int main()
{
    Function(1, 'a');
    Function('a',1);
    return 0;
}

在这里插入图片描述

这段代码同样定义两个相同的函数名,但是这两个函数的参数的顺序不同,参数的顺序不同,其本质是参数的类型不同,因此也构成了函数重载.

PS:如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分.
在这里插入图片描述

7.3:C++支持函数重载的原理—名字修饰

为什么C++支持函数重载,而C语言不支持函数重载呢?
在C/C++中,一个程序要运行起来,会经过以下几个阶段:预处理、编译、汇编、链接
在这里插入图片描述
请添加图片描述
回顾了上面编译与链接过程后,接下来我们来详解函数重载的原理
在这里插入图片描述

1.在实际项目中通常是由多个头文件与多个源文件构成,通过前面的编译链接的学习,我们可以知道,当test1.cpp调用了test2.cpp中定义的func函数时,编译链接时,test1.o的链接文件中没有func函数的地址,因为func函数是在test2.cpp中定义的,所以func函数的地址在test2.o中.那么该如何处理呢.

2.:所以链接阶段专门处理这种问题,链接器看到test1.o调用func函数,但是没有func函数的地址,就会到test2.o的符号表中找Add的地址,然后链接到一起。
3. 那么链接时,面对Add函数,链接接器会使用哪个名字去找呢?这里每个编译器都有自己的函数名修饰规则.Windows下的名字修饰规则有些复杂,这里博主简单演示下.

在这里插入图片描述

我们可以清晰地看到,在VS下
func(int,char)的函数名为 (?func@@YAXHD@Z)
func(char,int)的函数名为 (?func@@YAXDH@Z)
修饰后名字由"?“开头,接着是函数名+”@“符号结尾的函数名;然后再一个”@"表示函数的名称空间结束. windows下的函数名修饰规则相当赋值,博主这里使用Linux下来带着大家观察下.

在这里插入图片描述
我们将这样一段代码分别在C使用gcc与g++进行编译来观察下.

7.3.1:gcc下

在这里插入图片描述
在这里插入图片描述

请添加图片描述

我们可以清晰地看到,在linux下,采用gcc编译完成后,函数名字的修饰没有发行改变.

7.3.2:g++下

在这里插入图片描述
请添加图片描述

在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中。

通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载.

如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分。

好啦,家人们,关于C++入门(上)这块的相关细节知识,博主就讲到这里了,如果uu们觉得博主讲的不错的话,请动动你们滴滴的小手给博主点个赞,你们滴鼓励将成为博主源源不断滴动力!

评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值