C++入门基础知识

1.命名空间

C++ Namespace 详解
命名空间的定义格式为:(取自C++标准文档)

named-namespace-definition:       
            namespace identifier { namespace-body }
unnamed-namespace-definition:       
            namespace { namespace-body }
namespace-body:       
            declaration-seqopt

有名的命名空间:
namespace 命名空间名 {
声明序列可选
}

无名的命名空间:
namespace {
声明序列可选
}

所谓C++中的namespace,是指标识符的各种可见范围。C++标准程序库中的所有标识符都被定义于一个名为std的namespace中。
一、< iostream >和< iostream.h >
  < iostream >和< iostream.h >是不一样,前者没有后缀,实际上,在你的编译器include文件夹里面可以看到,二者是两个文件,打开文件就会发现,里面的代码是不一样的。
  后缀为.h的头文件c++标准已经明确提出不支持了,早些的实现将标准库功能定义在全局空间里,声明在带.h后缀的头文件里,c++标准为了 和C区别开,也为了正确使用命名空间,规定头文件不使用后缀.h。
  因此,当使用< iostream.h >时,相当于在c中调用库函数,使用的是全局命名空间,也就是早期的c++实现;当使 用< iostream >的时候,该头文件没有定义全局命名空间,必须使用namespace std;这样才能正确使用cout。
二、所谓namespace,是指标识符的各种可见范围。
  C++标准程序库中的所有标识符都被定义于一个名为std的namespace中。
  由于namespace的概念,使用C++标准程序库的任何标识符时,可以有三种选择:
  1、直接指定标识符。例如std::ostream而不是ostream。完整语句如下: std::cout << std::hex << 3.4 << std::endl;
  2、使用using关键字。 using std::cout; using std::endl; 以上程序可以写成 cout << std::hex << 3.4 << endl;
  3、最方便的就是使用using namespace std;
例如:

#include  
#include  
#include  
using namespace std; 
//这样命名空间std内定义的所有标识符都有效。就好像它们被声明为全局变量一样。那么以上语句可以如下写: 
cout<< hex << 3.4 <

因为标准库非常的庞大,所程序员在选择的类的名称或函数名时就很有可能和标准库中的某个名字相同。所以为了避免这种情况所造成的名字冲突,就 把标准库中的一切都被放在名字空间std中。但这又会带来了一个新问题。无数原有的C++代码都依赖于使用了多年的伪标准库中的功能,他们都是在全局空间 下的。 所以就有了< iostream.h >和< iostream >等等这样的头文件,一个是为了兼容以前的C++代码,一 个是为了支持新的标准。命名空间std封装的是标准程序库的名称,标准程序库为了和以前的头文件区别,一般不加”.h” 。

点击了解更多命名空间详解

2.C++基本的输入输出流

输入和输出是数据传送的过程,数据如流水一样从一处流向另一处。C++形象地将此过程称为流(stream)。C++的输入输出流是指由若干字节组成的字节序列,这些字节中的数据按顺序从一个对象传送到另一对象。流表示了信息从源到目的端的流动。在输入操作时,字节流从输入设备(如键盘、磁盘)流向内存,在输出操作时,字节流从内存流向输出设备(如屏幕、打印机、磁盘等)。流中的内容可以是ASCII字符、二进制形式的数据、图形图像、数字音频视频或其他形式的信息。

实际上,在内存中为每一个数据流开辟一个内存缓冲区,用来存放流中的数据。当用cout和插入运算符“<<”向显示器输出数据时,先将这些数据送到程序中的输出缓冲区保存,直到缓冲区满了或遇到endl,就将缓冲区中的全部数据送到显示器显示出来。在输入时,从键盘输入的数据先放在键盘缓冲区中,当按回车键时,键盘缓冲区中的数据输入到程序中的输入缓冲区,形成cin流,然后用提取运算符“>>”从输入缓冲区中提取数据送给程序中的有关变量。总之,流是与内存缓冲区相对应的,或者说,缓冲区中的数据就是流。

在C++中,输入输出流被定义为类。C++的I/0库中的类称为流类(streamclass)。用流类定义的对象称为流对象。

前面曾多次说明,cout和cin并不是C++语言中提供的语句,它们是iostream类的对象,在未学习类和对象时,在不致引起误解的前提下,为叙述方便,把它们称为cout语句和cin语句。正如C++并未提供赋值语句,只提供赋值表达式,在赋值表达式后面加分号就成了C++的语句,为方便起见,我们习惯称之为赋值语句。又如,在C语言中常用printf和scanf进行输出和输入,printf和scanf是C语言库函数中的输入输出函数,一般也习惯地将由printf和scanf函数构成的语句称为printf语句和scanf语句。在使用它们时,对其本来的概念要有准确的理解。

点击查看C++输入输出流详解

3.重载(C++为什么支持重载?)

1、首先,我们需要了解的是,在c中,要求在同一个作用域中,函数名唯一。就是不允许函数同名。
而在C++中,要求同一个作用域中函数签名唯一。函数签名是函数名+参数列表。就是说允许函数名相同但参数列表不同的函数存在。可见,函数重载跟返回类型没什么关系。
2、那么为什么C++允许函数签名唯一呢?
代码段在被编译器编译的时候,会根据函数名生成函数的调用地址。
C编译器编译之后,函数名不变。
而C++编译器编译之后,函数名就会发生命名置换。比如说代码中的函数是

int function(int a,int b,double c)  
    {  
        cout<

gcc编译,命名置换后,会变成_Z8functioniid。
其中_Z是gcc编译器的保留字,不同的编译器,生成的保留字也会不一样,8是函数名的字符数量,iid则是参数列表的缩写。
经过这样一个操作时候,即使是函数名相同,但只要参数列表不同,那么编译之后生成的函数名实际上是不同的。
3、需要注意的是,函数名会发生命名置换,同样,函数调用时也会发生置换。比如说:

int main()  
    {  
        function(2,5,2.36);  
    }  

这时,如果在C++中发生调用,不会出现问题。可是,如果是在C中调用,那么C的编译器是找不到经过C++编译器命名置换的函数地址的。因为C编译器没有命名置换,他调用的还是function这个函数名。于是出现了extern "C"这个关键字是告诉C++编译器不用命名替换,用C编译器的方式去编译。

extern "C"  
{  
    int function(int a,int b,double c)  
    {  
        cout<int main()  
    {  
        function(2,5,2.36);  
    }  
};  

这样就不会出现问题了。

4.C++缺省参数

在C++中参数可以设置缺省值,设置了缺省值之后,这个参数在调用时可以省略。

注意:设置缺省值的参数只能是最后的几个参数。也就是说某一个参数一旦设置了缺省值,其后而的参数也必须设置缺省值。例如:f()函数有3个参数,如果只设置第2个有缺省值,这就错了。因为调用时只输入2个参数时,系统不知道究竟是第2个参数还是第3个参数。

参数缺省值举例:

#include 
using namespace std;
int sum(int x=0, int y=100, int z=0) { return x+y+z; }
//int sum(int x, int y=100, int z=0) { ... }   //这是正确的
//int sum(int x, int y, int z=0) { ... }       //这也是正确的
//int plus(int x, int y=100, int z) { ... }    //这是错误的
int main ( )
{
    cout << sum() << endl;
    cout << sum(6) << endl;
    cout << sum(6, 10) << endl;
    cout << sum(6, 10, 20) << endl;
    return 0;
}

运行结果:
100
106
16
36

5.指针和引用(概念、使用方法、做参数、做返回值的作用,指针和引用的区别)

引用参数

从概念上讲。指针从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变。

而引用是一个别名,它在逻辑上不是独立的,它的存在具有依附性,所以引用必须在一开始就被初始化,而且其引用的对象在其整个生命周期中是不能被改变的(自始至终只能依附于同一个变量)。

在C++ 中,指针和引用经常用于函数的参数传递,然而,指针传递参数和引用传递参数是有本质上的不同的:

指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。(这里是在说实参指针本身的地址值不会变)

而在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

引用传递和指针传递是不同的,虽然它们都是在被调函数栈空间上的一个局部变量,但是任何对于引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。而对于指针传递的参数,如果改变被调函数中的指针地址,它将影响不到主调函数的相关变量。如果想通过指针参数传递来改变主调函数中的相关变量,那就得使用指向指针的指针,或者指针引用。

引用返回值

引用返回值的概念与引用参数相似,下面通过几个例子说明容易出错的地方。

(1)int &max(int i, int j){//错误的用法,i和j都是局部变量

return i>j?i:j;

}

(2)int m;

int &max(int i, int j){//正确

m = i>j?i:j;

return m;

}

(3)int &max(int &i, int &j){//正确

return i>j?i:j;

}

引用和指针的对比

★相同点:

●都是地址的概念;

指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。

★不同点:

●指针是一个实体,而引用仅是个别名;

●引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”,指针可以“见异思迁”;

●引用没有const ,指针有const ,const 的指针不可变;(具体指没有int& const a这种形式,而const int& a是有 的, 前者指引用本身即别名不可以改变,这是当然的,所以不需要这种形式,后者指引用所指的值不可以改变 )

●引用不能为空,指针可以为空;

●“sizeof 引用”得到的是所指向的变量( 对象) 的大小,而“sizeof 指针”得到的是指针本身的大小;

●指针和引用的自增(++) 运算意义不一样;

●引用是类型安全的,而指针不是 ( 引用比指针多了类型检查 )

你可能感兴趣的:(C++,namespace,c++)