C++入门知识

C++命名空间

命名空间是ANSI C++引入的可以有用户命名的作用域,用来处理程序中常见的同名冲突。 
在做一些大型工程的时候往往需要用户定义头文件,当一个工程中有好多头文件时,而这些头文件中有很多相同的变量名,编译器在进行预编译处理的时候,头文件中的内容取代了对应的#include指令,这样就在一个程序文件中出现了好几个相同的变量名,这时候编译器也不知道这个变量名代表哪一个,所以会在编译的时候报错。这也可以称为全局命名空间污染。这时候为了解决这个问题ANSI C++增加了命名空间。

所谓的命名空间:实际上就是一个有程序设计者命名的内存区域,程序设计者可以根据需要指定一些有名字的空间域,把一些全局实体分别放在各个命名空间中,从而与其他全局实体分隔开来。

namespace是命名空间的关键字。可以简单的理解命名空间就像操作系统下的文件,一般文件都放在不同的目录下,要查找文件直接找对应的路径就可以找到,这样就不怕重名了,但是命名空间不可以重名。

加入定义了一个命名空间nsl

namespace nsl
{
int a;
double b;
}

实际上a和b还是全局变量,仅仅将他们隐藏在nsl中,如果要在程序中用a和b,必须加上命名空间和作用域分辨符::,如nsl::a,nsl::b。这种用法称为命名空间限定,这些名字如nsl::a称为被限定名。 
命名空间的作用是建立一些互相分隔的作用域,把一些全局实体分隔开来,以免产生名字冲突。

而标准C++库的所有标识符都是一个名为std的命名空间中定义的,或者说标准头文件(如isstream)中函数、类、对象和类模板是在命名空间std中定义的。

所以在文件的开头前加入

using namespace std

这样在std中定义和声明的所有标识符在本文件中都可以作为全局变量来使用。但是在程序中不能出现和std的成员同名的标识符。

C++基本的输入输出流

输入输出的数据传送的过程在C++中称为流。 而C++中的输入输出流是指由若干个字节组成的字节序列,这些字节中的数据按顺序从一个对象传送到另一个对象。流表示了信息从源到目的端的流动。流的内容可以是ASCII字符、二进制形式的数据、图形图像、数字音频视频或其他形式的信息。

cin>>a;
cout<<a<<endl;

在内存中,系统会为每一个数据流开辟一个内存缓冲区,用来存放流里的数据。 在输入的时候,实际上是先把键盘上获取的数据存放在缓冲区里,当按回车时,缓冲区里的数据就会输入到输入缓冲区里形成cin流,然后用提取运算符>>从输入缓冲区里提取数据送达程序中的相关变量。 
输出时,实际上是现将程序的数据输出到输出缓冲区里,当缓冲区满了或者遇到endl时再把输出缓冲区里的数据输出到显示器上。 
可以说缓冲区里存的数据就是流。

函数重载

在C语言中一个程序中是不允许出现两个相同名字的函数的,但是如果要想写好几个功能相同的函数时, 就希望可以用一个函数名来实现不同的功能。 
C++允许用同一函数名定义多个函数,而这些函数的参数个数和参数类型可以不相同。这就是函数的重载。所谓重载,其实就是“一物多用”。

#include <iostream>
using namespace std;

void fun(int a)
{
}

void fun(char ch)
{
}

void fun(int a, char ch)
{}

void fun(char ch, int a)
{}

int main()
{
return 0;
}


C语言中上述程序是不可能编译过的,可以看看C语言在编译的时候具体是什么样的过程。 
以下测试均是在linux环境下,可以直观的看到编译过程

 
可以看到在编译函数的时候直接是把函数名载入,用函数名就可以直接区分几个不同的函数,而在C++编译的时候又是另一面。


在C++编译的时候,编译器将函数名处理成_Znfun,先看看是什么意思_Znfun是:返回类型+函数名+参数列表的形式,其中_Zn是返回类型,n的取值为函数名中字符数,fun为函数名,fun后面跟的就是参数的类型,i就是int,c就是char。 
所以从编译方式上就允许C++支持重载,C语言不支持重载。 
重载函数的参数个数,参数类型或参数顺序三者中必须至少有一种不同,函数返回值类型可以相同也可以不同。

缺省参数

缺省参数实际上就是在调用函数的时候,没有指定参数,会为函数提供一个缺省值。 
缺省参数有两种类型:全缺省和半缺省

#include <iostream>
using namespace std;

int fun(int a, int b=10)
{
return a+b;
}

int main()
{
cout<<fun(40)<<endl;
system("pause");
return 0;
}


就像这样的,在fun函数传参的时候只穿了a的值,而b没有传参,也就是说b的值被缺省了。这种就叫做半缺省。

#include <iostream>
using namespace std;

int fun(int a=10, int b=10)
{
return a+b;
}

int main()
{
cout<<fun()<<endl;
system("pause");
return 0;
}


像上面这种,如果在调用fun时,没有传递一个实参,这种就称为全缺省。 
缺省参数使用主要规则:调用时你只能从最后一个参数开始进行省略,换句话说,如果你要省略一个参数,你必须省略它后面所有的参数。

指针与引用

对于指针我们并不陌生,指针是存放地址空间的特殊变量,它指向的就是这块空间的地址。通常我们在调用函数的时候会传参数的地址,然后通过一个指针来接受它,而具体的调用就是在栈帧上开辟一块地址空间然后用指针指向这块地址,可见指针是非常灵活的。但是使用指针会让程序的运行变得不是那么的快。所以在C++中就出现了一个新的使用变量的方式–引用。 
先来看看什么是引用,引用相当于把原来的变量重新起了个名字,它不会占用额外的内存空间,通过引用的变量就可以直接对这个变量进行操作。 
引用的格式一般为:类型& + 引用变量名= 已定义过的变量名; 
引用的特点:

1、一个变量可取多个别名
2、引用必须初始化
3、引用只能在初始化的时候引用一次不能再定义为其他变量的别名。

先来看看常量的引用

int main() 
{
int a = 10;
int& c = a;
cout<<&a<<endl<<&c<<endl;
![Alt text](./17.png)

system("pause");
return 0;
}

定义一个整形变量a,然后引用变量名c,可以通过输出他们的地址看看是不是同一块空间

 
如果在一个变量前加上const限定,那么这个变量还可以被引用吗?

const int a = 10;
int& b = a;

 
编译报错,所以在引用const修饰过的变量时,不能够被直接引用,但是可以给引用变量名也加上const修饰,代表引用后的变量值不能被随便被改变,这样就保护了原数据的安全性。

再看看浮点型和整形之间的引用,我们知道在隐式转换时,浮点型转换为整形后,小数点后的数据全部丢失,那么引用时会出现什么呢?
float f = 1.11;
int& d = f;

 
编译出错,提示无法从float类型的值初始化int&类型的引用,因为原来的float在内存中存储在一块地址空间中,然后强制的修改这块空间为int类型的变量,那float肯定不答应啊,你这是直接想修改我的节奏啊!但是调皮的int可以给他加上const 修饰,说他肯定不会改变你的值,把你的空间也写上我的名字吧!这样就可以直接引用 float变量,但是还是会提出警告,可能会造成数据丢失。

函数参数引用

如果想要通过函数调用来交换两个变量的值时,在传递参数的时候通常传变量的地址,接收时用指针来接收。

int swap(int *a, int *b)
{
int tem = *a;
*a = *b;
*b = tmp;
}

这类通过指针接收参数叫指针传递,但是指针会增加程序的时间,刚刚了解到引用是给一个变量起个别名,给以通过修改这个别名的内容达到修改这个变量内容的目的。

int swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}

这类叫引用传递,它是直接通过修改别名值来达到交换目的的,这类传递的运行时间会比指针短。

传引用做返回值
int& fun(int a, int b)
{
int ret = a+b;
return ret;
}

int main()
{
int a = 10, b = 20;
int& c = fun(a, b);
cout<<c<<endl;
system("pause");
return 0;
}

先来看看通过传引用做返回值时是怎么样

 
返回时是返回值的地址存储在寄存器里,然后接收的时候是接收的这个变量的引用,虽然结果是正确的,但是实际上函数调用完之后,空间就被收回了。如果在调用一个其他的函数,那么这个接收的结果一定会发生变化,是一个随机的值。

void f(int a, int b)
{
int s = a+b;
}
int fun(int a, int b)
{
int ret = a+b;
return ret;
}
int main()
{
int a = 10, b = 20;
int c = fun(a, b);
cout<<c<<endl;

f(a, b);
cout<<c<<endl;
system("pause");
return 0;
}


所以的出一条结论:

1、不要返回一个临时变量的引用
2、如果返回对象出了当前函数的作用域依旧存在,则最好使用引用返回,这样效率更高。
引用和指针的区别和联系(注意笔试的时候非常喜欢考这个知识点)
1 . 引用只能在定义时初始化一次,之后不能改变指向其它变量(从一而终);指针变量的值可变。
2 . 引用必须指向有效的变量,指针可以为空。
3 . s izeof指针对象和引用对象的意义不一样。s izeof引用得到的是所指向的变量的大小,而s izeof指针是对象地址的大小。
4 . 指针和引用自增(+ + )自减(- - )意义不一样。
5 . 相对而言,引用比指针更安全。
关于指针和引用

指针比引用更灵活,但是也更危险。使用指针时一定要注意检查指针是否为空。指针所指的地址释放以后最好置0 ,否则可能存在野指针问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值