一、有了C语言,为什么还要创建C++语言
我们都知道C语言是偏底层的语言,几乎任何项目都可以用C语言去编写,那么,很多人(假装很多人)会有疑问,为什么还要在C语言的基础上去创建C++语言了?
答:其中一个目的是为了补C语言的坑
1.1 那么C语言有哪些坑了?
1.1.1 命名冲突的问题
例如:
int main()
{
int rand = 1;
printf("%d\n",rand); // 1
return 0;
}
// 这样确实可以打印rand,但是,一但包含了头文件stdlib.h
// rand就变成了关键字,在打印rand的时候就会报错
在C语言里面,这种问题怎么解决了?
答:唯一的解决办法就是换名字,变量名称,尽量不要使用关键字。
在命名变量的时候,不使用关键字,是不是就不存在命名冲突的问题了?
答:不是。
在一个大公司里面做项目的时候,每个人负责写程序的一部分,最后会将每个人写的程序合并起来,组成一个大项目。那么在合并的时候,也会出现命名冲突的情况。
例如:小明在他负责的项目部分,定义了一个变量名称a表示年龄大小,而小宏在他负责的项目部分也定义了一个变量名称a表示性别,单独运行的时候都没有问题。一旦合并项目时,就会出现命名冲突的问题,此时a到底是表示年龄还是性别?此时系统就会崩溃报错。
如果是C语言,这个问题如何解决了?
答:唯一的答案就是,改名字。
此时就会又出现一个问题,谁改名字?小明改还是小宏改?天台见面打一架?输的人去改明名字?
答:显然不可能,这是C语言的缺陷,难以弥补。
祖师爷本贾尼看不惯C语言的这些缺陷,于是就决定修BUG(C语言中不止这一个BUG,命名冲突只是其中一个),修改后C语言就大变样了,祖师爷就决定重新起个名字叫C++。
C++是在C的基础上做了些优化,升级,所以C++兼容C。
1.1.2 命名冲突的解决
定义一个私密空间,namespace HYQ
namespace HYQ
{
int rand = 0;
}
int main()
{
// printf("%d\n",rand); // 这样任然会报错
printf("%d\n",HYQ::rand); // ::是域作用限定符
// 这样正确(表示:去HYQ空间找一个rand的变量,并打印)
return 0;
}
如果不指明空间,系统默认去全局寻找rand,不会去自己定义的私密空间寻找
namespace HYQ
{
// 命名空间可以定义变量/函数/类型,甚至可以在嵌套一个命名空间
int rand = 10;
int Add(int left, int right)
{
return left + right;
}
struct Node
{
struct Node* next;
int val;
};
namespace xxx
{
int rand = 1;
}
}
int Add(int left,int right)
{
return (left + right) * 10;
}
int main()
{
printf("%d\n",rand); // 报错
// 如果不指明是哪一个rand,默认去全局找rand,不会去namespace找,所以报错(命名冲突)
printf("%d\n",HYQ::rand); // 10
// 指明了去HYQ空间找一个叫rand的变量,并以10进制的形式打印,即:10
printf("%d\n",HYQ::xxx::rand); // 1
// 去HYQ空间找一个叫xxx的私密空间,即:打印xxx里面的rand
printf("%d\n",Add(2,3)); // 50
// 默认调用的是命名空间外的Add函数
printf("%d\n",HYQ::Add(2,3)) // 5
// 指明了,去调用HYQ空间里面的Add函数,打印返回值
return 0;
}
每次去调用私密空间HYQ里面的变量、函数,每次都要使用,::域作用限定符,就很烦人!!
能不能解决一下这个问题?
答:可以。
第一种解决办法:全部授权
using namespace HYQ
namespace HYQ
{
int a = 10;
int Add(int left, int right)
{
return left + right;
}
}
int main()
{
//如果你定义的私密空间HYQ里面,有定义一个变量a和一个函数Add,而全局又没有变量a和函数Add
printf("%d\n",a);
printf("%d\n",Add(2,3));
//系统肯定报错,系统默认去全局寻找,而全局又没有,会报错:未定义。
printf("%d\n",HYQ::a); // 10
printf("%d\n",HYQ::Add(2,3)); // 5
// 每次调用HYQ空间里面的变量a和函数Add,都要使用HYQ::,就很凡人!!!
return 0;
}
解决办法:using namespace HYQ
namespace HYQ
{
int a = 10;
int Add(int left, int right)
{
return left + right;
}
}
// 全部展开(授权)
using namespace HYQ
int main()
{
printf("%d\n",a); // 10
printf("%d\n",Add(2,3)); // 5
return 0;
}
将私密空间全部展开,也会有问题,不安全
int a = 20;
namespace HYQ
{
int a = 10;
int Add(int left, int right)
{
return left + right;
}
}
// 全部展开(授权) 问题:不安全
using namespace HYQ
int main()
{
printf("%d\n",a);
// 报错,命名冲突,系统不知道调用的是哪一个a,没有明确说明,导致系统崩溃
return 0;
}
我可能经常使用Add函数,不用变量a,全部展开又存在不安全的问题,我又不想每次在使用前加,HYQ::
怎么解决了? 只能,部分展开(授权)
using HYQ::Add;
int a = 20;
namespace HYQ
{
int a = 10;
int Add(int left, int right)
{
return left + right;
}
}
// 部分展开(授权)
using HYQ::Add;
int main()
{
printf("%d\n",a); // 20
printf("%d\n",HYQ::a); // 10
printf("%d\n",Add(2,3)); // 5
return 0;
}
1.1.3 头文件不同
我们在写C语言时,通常会包含一个头文件#include <stdio.h>
,其中std表示standard(标准的意思),io表示in和out(输入输出),合起来就是标准的输入输出。
在写C++语言时,我们也会包含一个头文件#include <iostream>
,注意,这里没有.h(一些老古董编译器也许可以带.h,但是现在大部分编译器不带),io表示in和out(输入输出),stream表示流的意思,合起来是标准的输入输出流。
再包含头文件后,通常还会再写一个using namespace std
,其中std是C++标准库的命名空间,类似上面提到的HYQ。std这个命名空间里面包含很多变量、函数、类型等。
#include <iostream>
using namespace std;
int main()
{
// 打印hello world
printf("hello world\n");
// << 流插入运算符
cout << "hello world" << endl;
// cout里面的c是control表示控制台,out表示输出,合并起来表示:在控制台上输出hello world
// endl表示end of line,意思是换行,和\n的意思一样
return 0;
}
这个时候有人会有疑问,既然C语言里面已经有了一个printf语法,可以打印hello world,为什么还要创建一个新语法cout << "hello world" << endl;
答:这是对C语言的优化,为了方便。
int main()
{
int a = 1;
double b = 3.14;
// 如果用C语言打印a和b,必须明确指出是以什么形式打印
//(%d以10进制的形式打印,%lf以浮点数的形式打印)
printf("%d\n",a); // 1
printf("%lf\n",b); // 3.140000
printf("%.2lf\n",b); // 3.14,以浮点数的形式打印,保留两位有效数字
// 以C++的形式打印a和b
cout<<a<<endl; // 1
cout<<b<<endl; // 3.14
cout<<&a<<endl; // 00FAF7A4 (X86的环境)
cout<<&b<<endl; // 00FAF794 (X86的环境)
// 极大的简化了语法要求
return 0;
}
1.1.4 C++新语法—缺省参数
概念:缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。
void Func(int a = 1)
{
cout << a << endl;
}
int main()
{
Func(2); // 打印2
Func(); // 打印1
return 0;
}
void Func(int a = 10,int b = 20, int c = 30)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
}
int main()
{
Func(); // 打印10,20,30
// 半缺省
Func(1); // 打印1,20,30
Func(1,2);// 打印1,2,30
Func(1,2,3);// 打印1,2,3
return 0;
}
1.1.5 C++新语法—函数重载
*概念:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题
下面介绍几个函数重载的例子:
类型不同构成函数重载
int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}
double Add(double left, double right)
{
cout << "double Add(double left, double right)" << endl;
return left + right;
}
----------------------------------------------------------------------
类型不同构成函数重载
void Swap(int* p1, int* p2)
{
// ...
}
void Swap(double* p1, double* p2)
{
// ...
}
-----------------------------------------------------------------------
类型顺序不同构成函数重载
void f(int a, char b)
{
cout << "void f(int a, char b)" << endl;
}
void f(char a, int b)
{
cout << "void f(char a, int b)" << endl;
}
-----------------------------------------------------------------------
// 命名空间也能重载
namespace HYQ
{
void func(int x)
{}
}
namespace HYQ
{
void func(double x)
{}
}
-------------------------------------------------------------------------
// 参数个数不同构成函数重载
void func(int a)
{
cout <<"void func(int a)" << endl;
}
void func(int a, int b)
{
cout <<"void func(int a, int b)" << endl;
}
注意:返回值不同不能构成函数重载
void func(int a)
{
cout <<"void func(int a)" << endl;
}
void func(int a, int b = 1)
{
cout <<"void func(int a, int b = 1)" << endl;
}
----------------------------------------------------------------
// 上面两个函数构成函数重载,但是一般不这么用,因为存在歧义
int main()
{
func(1,2); // 可以正常调用,不报错
func(1); // 调用会报错,存在歧义,不知道调用哪个
}
第一次写博客,排版有点散漫,有意见可以提出来,我肯定不会改!!!😏😏😏
好啦,今天笔记到此为止,可以点进连接,欣赏一段美妙的音乐和舞蹈,放松一下。😊😊😊
舞蹈