座机前加区号:如0105992xxxx
输入您的电话号码,点击通话,稍后您将接到我们的电话,该通话对您完全免费,请放心接听!
从今天开始,我们正式进入C++的学习。本章节的任务就是利用代码介绍一些C++的基础知识。
C++是在C的基础上进行扩充的,C++对C的扩充,表现在两个方面:
1.在原来面向过程的基础上,对C语言的功能做了不少扩充;
2.增加了面向对象的机制。
本章节知识介绍一些C++在C的基础上扩充的一些东西,C++的兼容性方面的东西我们只是简单的提及,而不会专门的去开始介绍。
下面我们通过一个例子,正式开始进入学习C++。这是一个VS2010的集成开发环境,在下一章我会教大家如何使用这个集成开发环境去创建工程,构建程序,还有调试等等…..这是一个我们大家都非常熟悉的一个程序,只有一个main函数,输出了Hello World:
运行结果如下:
下面我们来分析一下这个程序的结构,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,比如我们可以这样写:
运行结果如下:这种风格的代码更加简洁。
因为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; }
运行结果如下:
字符串也有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是Standard Template Library的缩写,这个库包含了很多的类,这些类都是经过充分测试,并且都是十分高效的。使用它们我们不需要再去测试,因为标准模板库是由一批非常牛的程序员专家来实现的,高效并且稳定。有数据表明,它比百分之九十九的程序员写的代码都要高效。STL提供的功能有很多,我们后面都会讲到一些。希望大家都能够熟悉对STL的使用,前面的string,vector和cout都是在STL中实现的。
Copyright© 2019 巨立鑫 All Rights Reserved 皖ICP备17011067号-4 网址:http://www.jlxpx168.com 技术支持:巨立鑫软件技术部