引言:经过C语言和数据结构等编程知识的洗礼,到了暑假,我们就将要踏上C++编程语言的学习了,C++的学习难度比python等其他语言的学习难度更大,但是我们已经熟练地掌握了C语言的知识,相信学习起来C++应该还是会简单许多。那么,今天就让我们踏上C++的学习之路吧!
更多有关C语言和数据结构的知识详解可前往个人主页:计信猫
一,C++关键字——namespace
1,引子
让我们先看下面一段代码:
#include<stdio.h>
#include<stdlib.h>
//定义一个全局变量rand=10
int rand = 10;
int main()
{//打印rand的值printf("%d\n", rand);return 0;
}
在代码运行之后,我们的预期结果是控制台上成功打印10,。但是代码一走,却出现了如下的情况:
那么这段看似“完美无瑕”的代码又错在哪里了呢?其实答案很简单,在我们包含的头文件<stdlib.h>当中,就含有一个以rand来命名的函数,而当我们定义一个同名的全局变量rand的时候,就会造成歧义,导致编译器无法分辨rand是变量还是函数。
那么我们有没有什么办法来解决这个问题呢?当然,C++就为我们提功了一个很好的解决办法,那就是关键字——namespace。
2,命名空间的定义
定义命名空间,就需要使用到namespace关键字,只需要在关键字后面跟空间的名字,再接上一对{}即可,而{}中就可以存放成员变量的名字(变量可以为函数,变量,类型等)。
那么namespce关键字的使用就可以如下:
namespace test//该命名空间的名字为test
{//变量int rand = 10;//函数int Add(int a, int b){return a + b;}//类型struct node{int val;struct node* next;};
}
当然与此同时,namespace关键字也同时支持嵌套定义:
namespace n1
{namespace n2{//……成员}
}
并且,在不同的文件当中,同一个名称的命名空间可以被合并!如下:
//test.cpp文件当中
namespace n1
{//函数的定义int Add(int a, int b){return a + b;}
}
//test.h文件当中
namespace n1
{//函数的声明int Add(int a, int b);
}
3,命名空间的使用
那么,我们定义好了一个命名空间了,此时我们又应该使用什么方式去使用命名空间里边的成员呢?
方式一:
此时我们就需要用到预作用限定符——::,在使用时,我们只需要套用以下格式即可完成命名空间的成员的访问。形式如下:
命名空间名::命名空间成员名
所以,当我们遇到引子中所提到的问题时,我们就可以使用学得到知识很好地解决:
#include<stdio.h>
#include<stdlib.h>
//定义一个全局变量rand=10
namespace test
{//变量int rand = 10;
}
int main()
{//打印rand的值printf("%d\n", test::rand);//使用::return 0;
}
代码一走,结果如下:
方式二:
如果觉得某一个成员变量的使用次数很多,每一次使用该变量时觉得“::”非常的麻烦,那么我们可以使用using将某个成员变量的引入 ,这样就可以很好的避免以上的问题:
#include<stdio.h>
#include<stdlib.h>
namespace test
{//变量int a = 10;
}
//使用using引入成员变量
using test::a;
int main()
{//打印a的值printf("%d\n", a);return 0;
}
方式三:
我们也可以使用using直接将一整个命名空间展开,这时候使用命名空间里边的任何一个成员都不需要使用域作用限定符了!
#include<stdio.h>
#include<stdlib.h>
namespace test
{//变量int a = 10;//函数int Add(int a, int b){return a + b;}
}
//使用using展开命名空间
using namespace test;
int main()
{//打印a的值printf("%d\n", a);int c = Add(10, 20);printf("%d\n", c);return 0;
}
二,C++输出&输入
C++中输出和输入分别对应着cout(标准输出流对象——控制台)和cin(标准输入流对象——键盘),他们的作用分别相当于printf和scanf。因为它们的实现方式都存在于<iostream>头文件中的std命名空间当中,所以使用它们的时候都必须包含头文件<iostream>,并且以前面所学到的空间命名使用方式使用std。
在C++中,endl也包含于头文件<iostream>中,它的作用是换行。<<是流插入运算符,>>是流提取运算符。与C语言不同的是,在输入和输出时,C++可以自动识别变量类型!
那么现在,就让我们使用C++完成对变量的赋值和打印吧。
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
int main()
{int a;double b;char c;cout << "请输入abc的值" << endl;//分别对abc赋值cin >> a >> b >> c;cout << "abc的值如下" << endl;//打印abc的值cout << a << endl << b << endl << c << endl;return 0;
}
代码一走,结果如下:
三,缺省参数
1,缺省参数的概念
当我们在声明或者定义一个函数时,我们给该函数的参数一个缺省值。如果在使用该函数时,该参数没有对应的实参值,那么函数就会默认采用它的缺省值运行。
让我们来看一个例子:
//我们给10为缺省值
void func(int a = 10)
{cout << a << endl;
}
int main()
{func();//我们没有给该函数传参,所以函数将使用缺省值运行return 0;
}
代码一走,10就被打印在了控制台上。
2,缺省参数的分类
缺省参数可以被分为两类,一个是全缺省,另一个是半缺省。
●全缺省
//全缺省 void Add(int a=1,int b=3,int c=0);
●半缺省
//半缺省 void Add(int a,int b=3,int c=0);
其中,半缺省规定:只可以从右向左连续进行缺省,不可以有间隔。而在缺省参数这一整个知识点当中,还有一个规定,那就是缺省参数不可以同时出现在函数的声明和定义当中,缺省参数最好还是在函数的声明当中给出。
四,函数重载
在C++当中,函数可以拥有相同的名字,但是参数必须不同(参数的类型,个数,顺序)。
//参数类型不同
int Add(int a, int b);
double Add(double a, double b);//参数个数不同
void func(int a);
void func();//参数顺序不同
void Print(int a, char b);
void Print(char b, int a);
但是,在返回值不同,但是参数相同的情况下是不会构成重载函数,编译器会报错。
五,引用
1,引用的概念
在《水浒传》中,李逵在家中被称为“铁牛”,江湖上人称“黑旋风”,而这些称谓全都是指一个人——李逵。
所以在C++当中,引用就相当于给变量取了许多别名。引用的形式如下:
类型& 引用变量名(对象名)=引用实体名;
那么我们可以用以下例子来加强我们的理解:
int main()
{int a = 1;//开始引用int& b = a;int& c = a;int& d = b;++d;//打印各个变量的值cout << a << ' ' << b << ' ' << c << ' ' << d << endl;return 0;
}
那么代码一走,结果如下:
所以由此我们可以看出,bcd变量全部都是a的别名,只要其中一个变化,那么其他的也会跟着变化!
2,引用的作用
有了引用这个功能之后,那么我们就可以很轻松的写出以前的Swap交换变量函数。
//交换函数
void Swap(int& a, int& b)
{int tmp = a;a = b;b = tmp;
}
其中的形参a与b其实就是实参的引用。
而以前的二级指针也可以进行如下的表示:
LTNode** pphead—— > LTNode*& phead;
所以,引用主要用于函数的返回值和传参,使程序效率更高并且改变引用和被引用对象。
3,const引用
const引用主要作用于函数的参数传递,会与后面我们会学到的知识产生紧密的关联。而在使用const引用的时候,我么都必须遵守一个规则:权限只可缩小,不可放大。那么这句话具体指什么意思呢?让我们通过以下的例子来进行讲解:
const int a = 1;
//语句一
int& b = a;
//语句二
const int& c = a;
那么在这个例子当中,哪一条语句是正确的呢? 其实正确的语句是语句二,因为当我们以const修饰了整型变量a的时候,那么a此时的权限就是只可读,不可写。第一条语句的b引用变量却没有const修饰,那么此时的b就表示可读可写,相当于被引用变量a发生了权限放大,则发生了错误。
那么以下的例子也有着它们对应的错误,我们进行讲解:
//示例一
int b = 10;
const int& rb = b;//正确,因为rb有const修饰,只可读不可写,相当于b发生了权限缩小
//示例二
int a = 1;
int b = 2;
int& c = (a + b);//错误,因为(a+b)被视为一个临时对象,具有常量属性,只可读不可写,此处发生权限的放大
const int& d = (a + b);//正确,等号左右权限相同
//实例三
double d = 13.14;
int i = d;
int& ri = d;//错误,因为两变量类型不同
const int& ti = d;//正确,因为d类型转换为整型,此时就产生了d的整型临时对象,有常量属性
4,引用的规则
1,引用必须初始化。
int i = 0;
int& ri = i;//正确
int& bi;//错误,必须将bi初始化
2,可以给别名取别名。
int i = 0;
int& ri = i;
int& bi=ri;//给别名ri取别名为bi,它们都表示i
3,引用一旦引用一个实体,就不可以引用其他实体。
int i = 0;
int j = 0;
int& ri = i = j;//此时ri++,则j不会发生变化
4,引用不会开辟额外空间,指针会开辟额外空间。
5,sizeof中,引用的结果为引用类型的大小。
六,inline内联
inline内联可以算得上是一种对宏的替换。假如当我们想使用宏实现一个加法函数时,我们很容易发生少打了括号,多大了分号的错误,而inline内联很好的帮我们解决了这类问题。
// 宏实现加法函数
#define Add(x,y) ((x)+(y))
//inline内联
inline int Add(int x, int y)
{
int ret = x + y;
return ret;
}
这时候,内联函数就可以类似宏函数来使用,并且也会减少宏函数出现的一系列优先级的问题。但在使用内联函数的时候需要注意,不建议将定义与声明放在两个分离的文件当中,最好还是将内联函数放在.h文件当中。频繁调用的短小函数可以设计为内联函数。
七,nullptr
nullptr是C++专用的空指针,是一个关键字。nullptr可以通过类型强转转化为任意类型指针,但是不可以转化为整型0,从而避免了一些程序编写时的歧义问题。
八,结语
这就是我们在刚刚进入C++学习时需要知道的知识了,之后我会更新C++中类和对象的知识。希望这章节的知识点我讲的清楚明白,大家一起相互学习加油加油!!!