C++快速入门


从今天开始,我们正式进入C++的学习。本章节的任务就是利用代码介绍一些C++的基础知识。


C++是在C的基础上进行扩充的,C++对C的扩充,表现在两个方面: 


1.在原来面向过程的基础上,对C语言的功能做了不少扩充;


2.增加了面向对象的机制。


本章节知识介绍一些C++在C的基础上扩充的一些东西,C++的兼容性方面的东西我们只是简单的提及,而不会专门的去开始介绍。



 第一个函数- Hello World


下面我们通过一个例子,正式开始进入学习C++。这是一个VS2010的集成开发环境,在下一章我会教大家如何使用这个集成开发环境去创建工程,构建程序,还有调试等等…..这是一个我们大家都非常熟悉的一个程序,只有一个main函数,输出了Hello World:


start1.png


运行结果如下:


start2.png


下面我们来分析一下这个程序的结构,C语言的源文件是以.c结尾的,而C++的源文件是以.cpp结尾的。


//Hello World    
#include<iostream>
int main(int argc, char *argv[])
{
  Std::cout<<” Hello World”<<std::endl;
  return 0;
}


第一行


//双斜杠表示单行注释,编译器会跳过该行。多行注释/* 代码块*/,无论多少行,/* */中间的代码块都不会被编译。


第二行


以#号开始的被称为预处理值,在编译之前,预处理器会预先处理预处理指令。该行代码将iostream这个头文件中的所有内容都提取到这个程序中。iostream是标准输入输出流的头文件,在这个类内部声明的一个对象cout就是我们最常使用的输出对象。在C中,我们通常使用iostream.h头文件,而在C++中,头文件的.h可以省略。


第三行


main函数是C和C++程序的入口点,它是被执行的第一个函数,这个main函数有一个int的返回值,同时还有两个参数,这两个参数名是可以省略的。


第五行


将Hello World输入到控制台,通过定义在iostream中的cout实现的。Cout表示输出流,C++中有一个流的概念,在讲到输入输出的时候我们会介绍。std表示命名空间,用来处理不同代码段之间的变量名称冲突问题。我们多人开发一个软件的时候,经常会出现某个人定义的变量名与别人的变量名相同的问题,有了命名空间,每个人都有自己的命名空间,这样两个变量名即使相同编译器也会识别出它们是不一样的。endl也是定义在命名空间的,它表示回车换行,我们还可以通过输出\n的字符串来换行,效果同endl。


第六行


返回一个int值。



变量


在程序运行过程中可以改变值的量称之为变量。变量的命名方式:以字母和下划线开始。在C中,我们定义变量的方式一般都是在函数的初始位置进行定义。但是在C++中没有这个限制,你可以在任何地方进行声明。


注意:任何变量(对于全局变量,我们可以不进行初始化,这个变量会默认的用零进行初始化,但是这通常不是一个好的习惯。)使用之前你都需要给它一个初始值。


如果你没有给它赋值,将会怎么样呐?


int a;
std::cout<<a;

 

当你没有给a一个初始值的时候,存储a的变量的这一片内存是上次程序运行时遗留在那里的值,没有人知道那是一个怎样的值,反正那是一个垃圾值,这样的变量使用起来是没有意义的。



运算符


1.算术运算符:+  -  *  /


2.逻辑运算符: && 逻辑与 || 逻辑或  ! 逻辑非


3.关系运算符:<  >  <=  >=  !=

 

C++含有一个特殊的三元运算符?:,它需要三个参数: A?B:C   如果A为真,执行B,否则执行C,如果同if else来表示的话,就是


if(A){ 
B
}else{
C}

 

在很多情况下,它可以代替if else,比如我们可以这样写:


start3.png


运行结果如下:这种风格的代码更加简洁。


start4.png



数组


因为C与C++的三种循环结构是一样的,所以我们跳过循环,直接介绍数组。C提供了一种C风格的数组,我们定义一个含有十个int元素的数组:


int b[10]={200,3,3,3}; //数组中前四个元素被初始化,后面未初始化的元素自动初始化为0

 

C语言的这种数组是类型不安全的,我们在使用的时候经常容易下标越界,造成很多的问题。C++也提供了C++风格一种数组,我们应该这样来定义:


std::vector<int> C;

 

这是一个int类型的数组,vector翻译成中文就是向量,它也是定义在std这个命名空间中的。使用vector我们需要包含它的头文件,需要加上#include<vector>,vector是定义在标准模板库STL中的,标准模板库我们在后面也会介绍。


这个C++风格的数组现在是没有任何元素的,我们怎么给它添加元素呐?


C.push_back(10);
C.push_back(40);
C.push_back(33);


通过push_back()这个函数我们为它添加了两个元素,可以通过C风格一样的下标去访问它.如:


std::cout<<C[1]

 

这样就可以使用它了,C[1]就是一个int变量,它可以被赋值,也可以作为一个值去赋给别的变量。


我们可以通过调用size()这个函数获取它的长度。


我们可以通过for循环来遍历这个数组。


for(int i=0; i<c.size();i++)
{        std::cout<<C[i]<<endl;
}


运行结果如下:


start5.png



字符串


字符串也有C风格的形式,如:


char str[128]=”Hello world”; //c风格的字符串结尾总是有一个结束标志\0
char *str=”Hello world”;

 

在C++中,还添加了另外一种方式,那就是string类型。使用string也需要包含string.h这个头文件。


std::string  str=”Hello world”;

 

在c中,我们使用strcat这个函数来连接两个字符串,而在C++中,我们只需要+=就可以连接。如:


str+=”fgfdgdsggf”;

 

在string这个类中,不需要再用C中的strcmp来比较两个函数,直接使用==来比较。如:


Str==”fgfdgdsggf”;

 

可以说,C++风格的字符串使用起来是比较直观的,更符合我们对基本变量的使用方式,也建议大家多去使用这种风格。


我们之所以这么早就给大家介绍vector和string,也是希望大家在以后的学习中能够尽早的去使用它们,去替代C风格的数组和字符串,因为它们比较方便,同时是比较安全的。



函数


1.函数重载


在使用函数之前,我们应该声明它。函数的声明被称为函数的原型,表示函数的调用约定,包括调用参数的个数和类型,返回值,以及由谁去堆栈等等….


关于函数,我们首先介绍一下函数重载。函数重载时C++引入的一个新的特性。多个函数具有相同的函数名,这些函数中只是参数个数和类型不同,它们就构成了重载。


我们来定义一个函数,返回两个数之间的最大值。

 

int max(int a, int b);
double max(double a, double b);

 

如果我们通过max(20,40);来调用的话,它会根据参数的个数和类型来调用第一个函数。我们也可以看通过max(20.1,40.0);来调用第二个函数。


2.内联函数


函数调用,尤其是频繁的函数调用是有一定代价的,因为它伴随着参数的传递,代码的入栈,堆栈平衡等等….为了避免这种代价,我们可以将函数声明为内联函数。在声明为内联函数之后,编译器会将调用内联函数的地方展开,将内联函数的代码嵌入到调用内联函数的地方。


内联函数的使用方法,在函数声明的前面加上inline。如:


inline void func(){
int i=0;  i++;
}


如果我们在下面这样调用它:


func();


译器就会将代码嵌入到这个地方,成了这样的形式,这样就没有了函数的调用。


int i=0;  i++;


注意:使用内联函数可以节省运行时间,但是它有一个缺点,它会使你的应用程序体积增大。一般只是将代码段比较短(三到五行),调用比较频繁的函数声明为内联函数。即使你将一些复杂的函数声明为内联函数,具体是否嵌入代码这个是由编译器来决定的。编译器会根据一定的办法来判断它。


3.函数调用


C++的内存分为两部分,堆和栈。关于局部变量,函数参数的都是从栈中分配的。栈的特性是先入后出。大家学习过C,对函数的调用原理也比较清楚,函数的调用是通过栈来实现的。


下面我们来回顾一下栈:


比如a调用了B函数,首先a会讲B函数需要的参数入栈,接着会压入A中的返回地址,然后在栈中分配局部变量给函数使用。在函数执行完毕之后,在栈中会弹出函数返回地址到a中,此时分配给B函数的栈空间被回收。局部变量,函数参数占用的栈空间被释放。


下面我们来回顾一下堆:


内存是有操作系统管理的,应用程序可以向操作系统申请。但是应用程序向操作系统申请的代价是很大的,需要考虑到多线程的一些东西。这个时候就引入了堆。我们可以把堆比喻成向操作系统批发内存的零售商,它一次性从操作系统批发了一大片的内存,然后零售给我们的应用程序使用。因为没有多次从操作系统申请,所以操作代价比较小。堆一般随着应用程序的启动而分配,随着应用程序的退出而销毁。所以堆在整个运行期间都是可以使用的。

在C中,我们通过malloc来分配空间,用free来释放空间。


下面来举一个例子。


int *p=(int *)malloc(sizeof(int)*100); //申请一片可以存储一百个int变量的值的内存
if(!p){  //判断空间分配是否成功,分配失败就退出
return 0;
}
free (p); //释放内存
p=NULL; //当释放完这一片内存之后,p就已经不应该再指向这一片内存了。


为了防止误用,我们就把p指向NULL。如果不指向NULL,p就被称为野指针,野指针会导致一些问题。


在C++中,我们使用new来分配空间,用delete来释放空间。


int *p=new int[100]; //new会自动计算需要的长度,分配一连片的内存
if(!p){  //判断空间分配是否成功,分配失败就退出
return 0;
}
delete []p;  //上面是数组的分配空间,所以释放的时候需要在变量名前加[]  
p=NULL;


如果只是普通的变量申请和释放,只需要如此:


int *p=new int;

delete p; //不需要[],对应的申请内存的方式一定要匹配。


注意:使用new申请的内存在必须使用delete才可以释放,而释放的形式也必须匹配。



引用


引用是C++对C的重要扩充,它的作用是为变量起一个别名。假如一个变量A,我们想给它起一个别名B,我们可以这样定义:


int A=5;
int &B=A;


现在两个变量名A和B都是指内存中存储数值5的那一块内存,无论对A或者是B进行更改,都会导致这一块内存的值的改变。


注意:引用必须在定义的时候就初始化,一旦初始化之后就不可以更改。


比如int &B;这样只是声明没有初始化就是不可以的。一旦确定它是哪一个变量的别名,它就不可以被再次改变为别的变量的别名了。


引用使用的一个场景就是在参数传递下,默认情况下,函数参数传递是按照传值方式进行的,我们更改形参并不会对实参造成影响。在传入引用参数的时候,形参是实参的别名,更改形参会改变实参的值。关于函数传值,我们后面会介绍,这里只是简单的提及。



标准模板库(STL)


STL是Standard Template Library的缩写,这个库包含了很多的类,这些类都是经过充分测试,并且都是十分高效的。使用它们我们不需要再去测试,因为标准模板库是由一批非常牛的程序员专家来实现的,高效并且稳定。有数据表明,它比百分之九十九的程序员写的代码都要高效。STL提供的功能有很多,我们后面都会讲到一些。希望大家都能够熟悉对STL的使用,前面的string,vector和cout都是在STL中实现的。



【本文由麦子学院独家原创,转载请注明出处并保留原文链接】

logo
© 2012-2016 www.maiziedu.com
蜀ICP备13014270号-4 Version 5.0.0 release20160127

有一位课程导师想与你聊聊

客服热线 400-862-8862

回到顶部