C++基础入门知识学习(通俗详细讲解)

目录

  • 命名空间
  • 标注输入输出流
  • 缺省参数
  • 函数重载
  • 引用
  • 内联函数
  • C++11新特性auto关键字
  • C++11新特性基于范围的for循环
  • 关键字nullptr

命名空间(关键字namespace

在C++中我们会自己定义很多的变量、函数和类,这就同时要取各种变量名、函数名和类名。如果这些变量、函数和类的名称都存在与全局作用域中,就要刻意避免重复命名造成的麻烦,要避免命名冲突或名字污染,就要对这些定义的数据类型进行严格管理,namespace就是用来对各种标识符名称进行本地化管理,避免上述麻烦的关键字。
语法格式是 namespace 命名空间名称 {} 。大括号里面就是用来定义变量、函数和类的,这样的话,即使在其他作用域下有同样的标识符名称也不会造成冲突,要用到这些名称时只要注明相应的命名空间即可,当然是全局作用域下的名称,就不用注明了,这就把我们要用到的各种标识符名称很好地管理起来了。具体看一下代码实现。

// 1.普通的命名空间方式
namespace N1
{
	int add(int a, int b)     // 这里在N1里面定义add函数
	{
		return a + b;
	}
}
//2.命名空间可以嵌套
namespace N2
{
	int a = 5;
	namespace N3
	{
	    int b=10;
	}
}
//3.命名空间名称相同,最后编译器会将相同名称的命名空间合成一个
namspace N1
{
   int sub(int a, int b)
   {
     return  a-b;
   }
}
//要用到命名空间中的内容,有以下3种方法
//1 命名空间名称加作用域限定符
int main()
{
	std::cout << N2::a + N2::N3::b << std::endl;   //cout 和endl就是C++的命名空间std中的对象名称
	return 0;
}
//2.用using加命名空间加作用域限定符将所需名称引入
using std::cout;
using std::endl;
using N1::sub;
using N2::a;
using N2::N3::b;
int main()
{
	cout << sub(a, b) << endl;       //引入后的名称就可以直接使用
	return 0;
}
//3.使用using namespace 命名空间名称  直接将整个命名空间展开
using namespace std;
using namespace N1;
using namespace N2;
using namespace N2::N3;
int main()
{
	cout << add(a, b) << endl;    //三种方式对比:第一种是每次使用名称都要加作用域限定符,第二种是       
	return 0;                        //引入的名称可以直接使用,第三种引入整个命名空间后该命名空间所有成员都可以直接使用
}

我们平常学习C++时为了方便地使用C++标准库中的函数或对象就常在代码前面加上using namespace std;

标注输入输出流

C++中的标准输入(键盘)和标准输出(控制台)所用的关键字分别是cincout,需要包含头文件iostream以及标准命名空间std,与C语言的scanfprintf有很大的不同,使用cout不用增加数据格式控制如%d,%f等,它会进行自动类型推导并输出,使用cin时同样不用加数据格式控制符,在键盘上输入当类型不同也会发生隐式类型转换。

int main()
{
	int a;
	double b;
	cin >> a>>b;
	cout << a <<" "<<b << endl;
	return 0;          //cin与>>配合使用 cout与<<配合使用 endl相当于换行符\n
}

缺省参数

C++函数的参数列表中可以有缺省参数,就是默认参数的意思,在调用函数传参时给了具体的值就用具体值,没有传实参拷贝值时就用默认的值。

//1.全缺省参数
void myprint1(int a = 2, int b = 5, int c = 10)
{
	cout << a + b + c << endl;
}
//2.半缺省参数
void myprint2(int a, int b = 5, int c = 10)
{
	cout << a + b + c << endl;
}
int main()
{
    myprint1() ;
	myprint1(10);
	 myprint2(5);
	 myprint2(3, 4, 5);
	return 0;
}

在这里插入图片描述
注意:

    1. 半缺省参数必须从右往左依次来给出,不能间隔着给
    1. 缺省参数不能在函数声明和定义中同时出现
    1. 缺省值必须是常量或者全局变量
  •       4. C语言不支持这样的语法
    

函数重载

C++中有函数重载的概念,简单地说就是允许定义函数名相同的函数,在调用函数时,根据函数传入参数类型不同、参数个数不同,参数顺序不同来区分是要调用同名函数中的哪一个函数。所用发生函数重载的情形相应的就有以下三种。


void func(int a, double b)
{
   cout << "int和double" << endl;
}
void func(int a)                    //三个函数名都为func但两两比较有参数个数不同、参数类型不同、顺序不同
{
   cout << "int" << endl;         
}
void func(double a, int b) 
{
   cout << "double int" << endl;
}
int main()
{
   func(1);                        //因此这里调用func会按照函数重载规则去调用相应的函数
   func(1, 1.5);
   func(2.5, 1);
   return 0;
}

在这里插入图片描述

函数重载机制

程序运行要经历预处理、编译、汇编和链接。当我们调用函数时在链接阶段,连接器就要按照函数名到相应的符号表中去找对应函数的入口地址去执行哪里的代码,C语言不支持函数重载就是因为符号表中的函数名就为函数定义时的函数名,而C++符号表中函数名有特殊的函数名修饰规则,在原函数名的基础上,编译器将函数参数类型信息添加到修改后的名字中,最后生成的符号表中的函数名是唯一对应一个函数入口地址的。这也解释了函数返回类型不是产生重载的因素。

引用(关键字&)

引用可以通俗地理解给变量取别名,当我们定义一个变量时会在内存中相应地申请一块空间,我们为使用这块空间取了个名字,方便我们操纵这块空间的值,使用引用就为这块空间取了另外一个名字,使用另外的名字也可以来操纵这块空间的值。
在这里插入图片描述
引用的用法:类型 & 别名=引用实体
要注意引用类型必须和引用实体是同种类型的

//引用的特性
int main()
{
	int a = 10,t=5;
	int& b = a;       //1.引用在定义时就要初始化
	int& c = a;       //2.一个变量可以有多个引用,即可以取多个别名
	//int& c = t;        //3.引用一旦引用一个实体,再不能引用其他实体
	cout << &a << " " << &b << " " << &c << endl;
	return 0;
}

在这里插入图片描述

常引用

int main()
{
	//int& a = 10;   //类型不同 a是变量,10是常量
	const int& a = 10;  
	const int b = 5;
	//int& c = b;  //类型不同  从b到c权限放大,不允许这样,
	int e = 8;
	const int& h = e;  //从e到h变量到常量是权限的缩小,循序这样
	double d = 3.14;
	//int& f = d;   //类型不匹配
	const int& f = d;   //这里发生隐式类型转化d是double类型,产生临时拷贝值是int型具有常属性,f是临时拷贝值的引用
   return 0;
}

引用的用法

1.作函数参数

int add(int& a,int& b)
{
    return a+b;
}

2.作返回类型

int& add(int a,int b)
{
   static int c=a+b;
   return c;
}

注意:如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。

引用与指针的区别

  1. 引用在定义时必须初始化,指针没有要求
  2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
  3. 没有NULL引用,但有NULL指针
  4. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
  5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  6. 有多级指针,但是没有多级引用
  7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  8. 引用比指针使用起来相对更安全

引用传参和值传参以及引用返回和值返回效率对比

值传参和传值返回都是产生临时变量返回临时变量,中间有空间开辟和释放等操作,相比之下引用传参和返回就没有这些过程,所以使用引用可以提高运行效率。

内联函数(关键字 inline)

用法就是在普通函数定义的开头加上修饰字inline,作用是编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,达到提升程序运行的效率。

inline int maxnum(int a,int b)
{
   return (a>b)?a:b;
}

内联函数特性

  1. inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的函数不适宜使用作为内联函数
  2. inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。
  3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

C++11新特性auto关键字

C++11开始auto是自动推导定义数据类型,用代码解释。

#include<vector>
int main()
{
	int a=10;
	auto b = a;                 //定义变量b就能推导它是int型,值是10
	double c=3.14;
	auto d = c;                   // 同样d就是double型,值3.14
	cout << typeid(b).name() << endl;
	cout << typeid(d).name() << endl;
	cout << b << endl;
	cout << d << endl;  
	vector<int>v1;
	for (int i = 1; i < 5; i++)
	{
		v1.push_back(i);   //上述用auto来推导int ,double等类型并没有体现auto带来的实质性好处
	}            //在stl中有很多类型名非常长,就能体现auto带来的便利了,这里v1.begin()返回的类型即变量
	for (auto it = v1.begin(); it != v1.end(); it++)//it的类型是vector<int>::iterator。auto it = v1.begin()和vector<int>::iterator it = v1.begin()是等价的
	{
		cout << *it << " ";
	}
	return 0;
}

在这里插入图片描述

auto使用细则

1.用auto来声明指针类型时,auto 和auto * 没有区别,但声明引用类型时一定要用 auto &
2.当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

int main()
{
	int a = 10;
	double b = 3.14;
	//auto c = a, d = b;  // 这里已经默认auto 推导的类型时int, 但后面b是double不能赋值给d
	return 0;
}

注意auto不能用来作形参推导类型

void func(auto a)   //这是不允许的

不能用来定义数组

auto  arr[ ] ={3,5,7};  //不能这样定义数组

C++11新特性基于范围的for循环

范围for循环的用法

int main()
{
	int arr[] = { 1,2,3,4,5 };
	for (auto e : arr)        //必须传入数组名,自动依据数组元素个数推导循坏次数,单趟把数组的一个元素
	{                         //赋值给e,通过这种形式遍历数组。
		cout << e << " ";
	}
	for (auto& e : arr)  //加上引用符& 每趟循环生成不同的e来引用数组的元素从而操纵数组内容,这里就实现了数组各个元素+1的操作
	{
		e++;
	}
	cout << endl;
	for (auto e : arr)      
	{                        
		cout << e << " ";
	}
	return 0;
}

注意

void myprint(int arr[])
{
for (auto e : arr)      //这里范围for的效果就会失效,应为arr一定要是数组名,而这里通过传参的方法时arr已经退化为指针了,范围不能确定了。
	{                        
		cout << e << " ";
	}
}

关键字nullptr

在C++中关于null定义的代码如下

#ifndef NULL
#ifdef __cplusplus
#define NULL 0        //所以null在C++中是等同与整形数字0
#else
#define NULL ((void *)0)
#endif
#endif
void func(int)             //
{
	cout << "int" << endl;
}
void func(int*)
{
	cout << "int*" << endl;
}
int main()
{
	func(0);
	func(NULL);    // 我们本意是希望参数是空指针NULL走第二个函数但实际是走第一个函数
	func((int*)NULL);    //只用强制转换和参数是nullptr时才走第二个函数
		func(nullptr);
	return 0;
}

在这里插入图片描述
引入nullptr就是希望避免NULL是指针还是整形0的混淆引起的特定情形下的错误。
注意

  1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。
  2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
  3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。
  • 20
    点赞
  • 99
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值