栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

初识C++

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

初识C++

写在前面

这是我第一次接触到C++,之前对它的大名可谓是如雷贯耳.这两天有人问我学习C++的感觉怎么样?对此我想说,很难.C++的细节很多,要求我们比学习C语言更加细心,我不是没有学习过OOP语言,但是刚开始接触到还是感觉有点吃力,不过这是一种很令人高兴的情况,这代表你在进步,要是我们在一直学习已经站掌握的知识,又怎么会提高我们呢?我学习C++的方法是通过看网上一些大佬讲解的视频,然后通过一些经典的书籍来补充,后面和大家分享一下博客,做些OJ题.这种方法对我来说还是挺不错的,大家要是没有方法,可以先试试这个,后面可以选择更加适合自己的方法.


什么是C++

这里我就不和大家分享了,一般我们看每一本书都会谈到C++的历史,我想先和大家来一起学习这门语言,后面到最后专门写一篇博客来专门谈谈历史的一些趣闻趣事,这在我们面试的时候可以和面试官聊聊.

这里我先提一点,C++可以认为是对C语言一些缺陷的补充,C++编译器支持C语言语言的90%以上,类似函数的命名,scanf,printf都是支持的.

如何创建一个C++文件

前面我和大家分享C语言时用的环境大部分都是VS2019,这里用来做C++集成开发环境还是可以的,创建文件的步骤和之前是一样的,就是在最后一步,我们的文件的后缀名是.cpp,这样VS就会调用C++的编译器.

Hello word

我们精通各种语言的Hello word,谈个玩笑.Hello word在我心中有不一样的意义,它敲开了很多人对计算机的大门,在这里我们仍旧打印出这句话,标志着我们正式进入C++,大家对代码要是有什么不理解的话,先不要着急,后面我们会一一解剖。

#include 
using namespace std;

int main()
{
	cout << "hello world" << endl;
	return 0;
}

命名空间

我们总是看到有人一写代码就把using namespace std;,这是什么?这是必须的吗?一般的人可能就会谈到记住就可以了,不用管原理,但是对于我们这些要进大厂的人来说,这是很重要的.

我们先来看一个例子,下面的代码可以跑过吗,为什么不能跑过?

void f()
{

}

int f = 0;

int main()
{
	printf("%d", f);
	return 0;
}

我们可以看出,第一个f表示的是函数名,第二个是一个全部变量,这就给编译器一种误导,这在语法上就是一种错误.在C语言这种错误只能有一种解决方法,函数改名或者是变量改名,这就会造成这样一种情况:

函数说:你改名字吧,变量,我这都被调用几百次了.变量反驳到,我这都用了上千次了,你说谁改?这种情况我们该怎么办,在C语言中我们我们只能一个一个修改.但是在C++中我们可以通过一种命名空间的凡是来解决.有人可能会感到纠结,我会这么大意,让它们重名?开玩笑!是的,我们自己当然可以确定自己的的命名不重复,可是大家不要忘了,一个很大的程序是多人协作共同完成的,你可以确定你们几个人甚至几十个人命名不重复,谁都不能保证.

namespace

C++解决命名重复就是使用namespace关键字,这是C++新增的一个,通过这个关键字我们可以把自己定义的变量隔离出来,就是想箱子一样,每一个人拥有一个属于自己箱子,用到的时候,自己打开自己的箱子就可以了.我们后面具体在谈,下面先看一个例子.

我们都知道下面的代码会打印出什么结果,局部优先,结果就是0,但是这里我先要得到全局变量a的结果,也就是10,怎么弄?

int a = 10;

int main()
{
	int a = 0;
	printf("a = %dn", a);
	return 0;
}
域作用限定符 ::

我们可以通过一个::来解决这个问题,我们可以命名空间就是一个箱子,::可以把箱子打开拿到里面的内容.箱子:: 箱子里面的东西,当箱子省略时,它回去全局变量区那寻找.这就是我们可以得到10的原因.

int a = 10;

int main()
{
	int a = 0;
	printf("a = %dn", ::a);
	return 0;
}

创建命名空间

现在我们就可以放开手和大家分享了,前面的铺垫一已经够我们现在继续说下去了,每一个人都可以创建自己的命名空间,这样的话我们几个人之间就可以不担心命名重复了,使用namespace就可以创建了.

张三和李四都独自创建了自己的命名空间,这样即使后面它的命名出现错误也不会报错

//张三的命名空间
namespace N1
{
	int a;
}

//李四的命名空间
namespace N2
{
	int a;
}
int main()
{
	N1::a = 10;
	N2::a = 20;
	printf("%dn", N1::a);
	printf("%dn", N2::a);
	return 0;
}

这里我想谈谈下面几点,这些有助于我们理解命名空间

上面的变命名的变量是全局变量,在我们定义这两个变量后,会在内存中开辟不同的空间.

int main()
{
	printf("%pn", &(N1::a));
	printf("%pn", &(N2::a));
	return 0;
}

命名空间里面可以有什么

这个问题很好,命名空间里面可以包含三类事物.

  1. 全局变量
  2. 函数
  3. 结构体

前面的全局变量已经和大家分享过了,这里从函数这个比较简单的说起.

和全局变量一样,我们为了防止函数命名重复,也可以把函数放到命名空间里面.

namespace byte
{
	void func()
	{
		printf("这是 byte 空间里面呢的函数n");
	}
}

int main()
{
	byte::func();
	return 0;
}

在来谈谈结构体,关于结构,要是很上面说的一样就有点落于俗套了,这个我在命名空间重复嵌套这里谈,会好好说说.

命名空间的嵌套

一个大型工程,里面可能还要分为很多组别,例如有数据组的,有测试组的,这样的话,我们希望可以对命名空间进行嵌套,这样就可以避免重复

下面就是重复嵌套的命名空间

namespace byte
{
	namespace data
	{
        int a;
	}
	namespace test
	{
        int a;
	}
}

这里谈一谈,但我们使用命名空间存储结构体会发什么什么?注意这里的结构体里面存储的是类型,不是变量.当然它可以存储结构体变量.

下面的的命名空间我们我们可以嵌套几个,里面就可以定义我们的结构体了.

namespace byte
{
	//数据组
	namespace data
	{
		struct ListNode
		{
			int val;
			struct ListNode* next;
		};
	}
	//缓存组
	namespace cache
	{
		struct ListNode
		{
			int val;
			struct ListNode* next;
		};
	}
}
命名空间名字重复

当我们定义的命名空间名字重复后,编译器会自动把他整合在一起,也是说名字一样的命名空间可以看作同一个空间.

namespace N1
{
	int a;
	int b;
}
namespace N1
{
	int a;
	int b;
}

如何使用命名空间里面的元素

我想使用命名空间里面的元素,有没有办法内?

使用域作用限定符::

前面我们已经谈过域作用限定符::了,刚才的众多例子中也多次使用了这个域作用限定符,这个域作用限定符的作用就像是可以打开箱子一样,拿出里面的元素.这里具体谈谈.

namespace N1
{
	int a;
	int b;
}

int main()
{
	N1::a = 1;
	N1::b = 2;
	printf("%d %d", N1::a, N1::a);
	return 0;
}

使用域作用限定符::,我们使用哪个就可以拿出来哪个,这种方法比较谨慎,安全性也比较高,不过有一个缺点就是,有一点麻烦.

打开全部的元素

前面谈了有一点麻烦,这里有一个简单的方法,我们可以直接打开命名空间里面的全不元素,大家一看就知道了.

打开命名空间里面的所有元素,直接使用这些就可以了.这样相当于没有定义命名空间.

namespace N1
{
	int a;
	int b;
}

using namespace N1;  //打开 N1 的命名空间
int main()
{
	a = 20;       //直接使用
	b = 10;       //直接使用
	printf("%d %d", a, b);
	return 0;
}

一些缺陷在下面谈.

打开部分元素

打开全部的元素这种也会带来一部分问题,当我们打开多个命名空间的时候,既有可能会出现命名一样的情况,这里编译器就会报错,这里也有一个折中的方法,用哪个就把它从名宁空间里面拿出来.

我们打开了变量 a,就可以把他放开了.

namespace N1
{
	int a;
	int b;
}

using N1::a;

int main()
{
	a = 20;       //直接使用
	N1::b = 10;   //不能直接使用
	printf("%d %d", a, N1::b);
	return 0;
}

我们这里来个测试,大家应该可以看懂了.

namespace byte
{
	int a;
	//数据组
	namespace data
	{
		struct ListNode
		{
			int val;
			struct ListNode* next;
		};
	}
	//缓存组
	namespace cache
	{
		int b;
		struct ListNode
		{
			int val;
			struct ListNode* next;
		};
	}
}
using namespace byte;
using namespace byte::data;
using byte::cache::b;
int main()
{
	//用域作用限定符
	byte::a = 10;
	struct byte::cache::ListNode n1; //有没有struct都可以

	//打开  byte命名空间
	a = 10;
	struct data::ListNode n2;  //有没有struct都可以

	//打开  byte命名空间 和  data
	struct ListNode n3;
	
	//使用 cache的的部分元素
	b = 20;
	return 0;
}


解释using namespace std;

现在我们就可以知道了他就是打开名为std命名空间,这句话不是必须的,我们也是这样用.

int main()
{
	std::cout << "hello word" << std::endl;
	return 0;
}

C++输入和输出

我们都知道,C++ 支持C语言的很多语法,这里输入输出可以使用scanf和printf,但是C++也给出了一些其他的方法,而且更加方便,我们先来看看具体如何做.

#include 

using namespace std;

int main()
{
	int a = 0;
	double d = 0.0f;
	cin >> a;
	cin >> d;
	cout << a;
	cout << d;
	return 0;
}

注意:早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件
即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,规定C++头文
件不带.h;旧编译器(vc 6.0)中还支持格式,后续编译器已不支持,因此推荐使用
+std的方式。

这里我要谈一些东西

  • 在使用pritnf时,我们需要指定数据的格式,但是上面这种方法不需要,编译器会自动识别并匹配.
  • cin是标准输入流,从键盘中中输入,cout是输出流,输出到屏幕上
  • >>和<<可以理解为方向哎u你,例如 cin>>a,就是数据从键盘上输入到a中.cout<
  • 大家疑惑插入操作符<<和左移操作符一样,这实际上是操作符的重载。我们现在不需要了解这么多.

如何进行换行?,上面的结果我很不适应,可以换一个行吗? 可以的

using namespace std;

int main()
{
	int a = 0;
	double d = 0.0f;
	cin >> a;
	cin >> d;
	cout << "a = " <缺省函数.不知道大家知不知道备胎,就是有事的时候找你来帮忙,没事的时候就吊着你.缺省函数也是如此,我们先来看看.

这里的func就是一个缺省函数,如果我们不传入参数,a就会赋值10,就是那个备胎,传入了,就可以把备胎给扔掉了.

void func(int a = 10)
{
	printf("a == %dn", a);
}
int main()
{
	func();
	func(20);
	return 0;
}

缺省函数的应用

这里我给出一个应用,我们在之前分享数据结构的时候,经常会出现初始化的情况,这里我先义队列为例子

这样我们初始化时就不需要给函数传入多少个空间,一当完成初始化就会有4个数据的空间,第一次插入的时候就不需要扩容了.

typedef struct Queue
{
	int* elem;
	int cap;
	int size;
} Queue;

void QueueInit(Queue* ps, int cap = 4)
{
	ps->elem = (int*)malloc(sizeof(int) * cap);
	ps->cap = cap;
	ps->size = 0;
}
int main()
{
	Queue qu;
	QueueInit(&qu);
	return 0;
}
多参数的缺省函数

只有一个函数的缺省函数可能体现不出来特性,下面我们使用三个参数的.

全部缺省
using namespace std;

void func(int a = 1, int b = 2, int c = 3)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
}
int main()
{
	func();
	cout << endl;
	func(111);
	cout << endl;

	func(111,222);
	cout << endl;

	func(111,222,333);
	return 0;
}

部分缺省

对于多参数的函数而言,我们可以缺省一部分的参数,不过参数缺省还需要一定的要求.

半缺省参数必须从右往左依次来给出,不能间隔着给

void func(int a,int b = 2, int c = 3)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
}

缺省函数的注意事项

我们来看看这些注意事项

  • 半缺省参数必须从右往左依次来给出,不能间隔着给
  • 缺省参数不能在函数声明和定义中同时出现
  • 缺省值必须是常量或者全局变量

第一个我们已经谈过了,这里主要谈第二条,我么缺省函数在声明的时候如何声明

void func(int a = 30);
void func(int a = 30) 
{
	cout << a << endl;
}

int main()
{
	func();
	return 0;
}

当函数声明遇到函数声明和函数实现的时候,编译器不到使用哪个缺省值,即使有时他们是相同的.这样就会报错.这里我来谈谈

声明给,定义不给

我是使用的三个文件来演示的,

//Test.h文件中
#include 

using namespace std;

void func(int a = 20);

//test.cpp中
void func(int a)
{
	cout << a << endl;
}

//mian.cpp中
#include "Test.h"

int main()
{
	func();
	func(11);
	return 0;
}

声明不给,定义给

这种请情况会报错.

//Test.h文件中
#include 

using namespace std;

void func(int a);

//test.cpp中
void func(int a = 20)
{
	cout << a << endl;
}

//mian.cpp中
#include "Test.h"

int main()
{
	func();
	func(11);
	return 0;
}

我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号