面向对象设计主要特征是程序=对象+消息,对象是基本元素,对象接收到消息后,启动有关方法完成操做。ios
面向对象程序设计的基本特征有:抽象、封装、继承和多态。c++
c++支持编译时的多态和运行时的多态,编译时的多态经过函数重载实现,运行时的多态经过虚函数实现。数组
c++经过对c进行扩充,是面向过程程序设计和面向对象设计的混合型程序设计语言。函数
c++程序通常由类的声明和类的使用两大部分组成。this
c++对c的扩充:spa
l c++除了保留c的进行输入/输出操做时常使用的printf()和scanf()函数外,新增标准输入流对象cin和标准输出对象cout。cin遇到空格,就认为本数据输入结束并检查输入数据与变量的匹配状况。c++增长了操纵符对输出数据格式进行控制,如换行操纵符endl。设计
l 在c语言中全局变量必须声明在任何函数以前,局部变量必须集中在可执行语句以前,而c++容许变量声明可与可执行语句交替出现。指针
l 在c++中,结构名、联合名、枚举名都是类型名。能够像定义对象那样,定义结构体、联合体、枚举。没必要在前面冠以struct、union、enum。对象
l c语言建议为每个函数创建函数原型,c++必须创建函数原型,以便在编译时进行类型检查。继承
l c语言经常使用#define 来定义常量,可是容易出错,c++推荐用const修饰符。
l 内联函数以空间换时间的方式下降函数调用时的系统开销,但要求内联函数体内不含有负杂的控制语句,也不能过长,省得程序编译后体量过大。c++中一个函数在类体内则被隐式的指定为内联函数,也能够用inline显式的指定内联函数。
l 能够定义带有默认参数的函数。
l 用户能够重载函数,即在同一做用域中,能够定义函数名相同的函数,只要函数参数类型不一样或者参数个数不一样或者兼而有之。
l 做用域标识符::c语言中函数内若有和全局变量同名的局部变量,则全局变量会被屏蔽没法访问,而c++中能够在变量名前面使用::代表是使用全局变量。
l 计算机内存会被分为四个区:程序代码区、全程数据区、栈、堆。只有堆可由用户分配和释放。c语言中使用函数malloc函数和free来动态管理内存,c++提供了运算符new、delete来作一样的工做。
l 引用,c++中引用就是变量的别名,故又称别名。引用和原变量名指向内存中的同一区域。
l 传递函数参数的三种状况,一、将变量名做为函数参数,这是“传值调用”,是单向传递,在函数运行过程当中,形参的变化不会传递给实参,二、指针变量做为函数参数,这是“传址调用”,是双向传递,三、引用做为函数参数,也是“传址调用”双向传递。
l 一般一个函数不能直接用在赋值运算符的左边,例如
index(2)=25;这是不容许的,可是使用引用返回函数值就能够这么写了:
int& index(int i)
{
return a[i];
}
index(2)=25;这是容许的,至关于a[2]=25;要注意的是引用不是一种数据类型,因此不能定义引用的引用、引用的指针、引用的数组。
类的构成:类和结构体的扩种形式十分类似,类生命中包括数据和函数,分别称为数据成员和成员函数,数据成员和成员函数有公有、保护、私有三种访问权限。通常状况下,类体中只给出成员函数原型,而函数体的定义放在类外。须要注意的是不能在类声明中给数据成员赋初值。
相同类型的对象能够相互赋值,如a=b,对象之间的赋值,仅仅是对数据成员的赋值,不一样的对象的数据成员占据不一样的存储空间而不一样对象的成员函数是占有同一个函数代码段,没法对他们赋值。当类体中存在指针时,使用赋值运算符进行赋值,可能会产生问题,即所谓的“浅拷贝”和“深拷贝”问题,浅拷贝时,由于含有指针,两个对象指针指向同一块内存区域,同一个对象调用析构函数时,该块内存被释放,当另外一个也调用析构函数,一样要释放该块内存,而同一块内存不能被释放两次,这时便会出现问题,要解决该类问题,就须要使用“深拷贝”。
构造函数是特殊的成员函数,其函数名必须和类名相同,能够有任意的参数但不能有返回值甚至void也不行,它不须要用户调用,在定义对象时自动执行且只执行一次,为对象分配空间,进行初始化。
c++提供了除赋值运算符以外的初始化数据成员的方法,即成员初始化列表。对于用const修饰的数据成员,或是引用类型的数据成员,是不容许用赋值语句直接赋值的,只能用成员初始化列表进行初始化。
析构函数是另外一种特殊成员函数,一般用于撤销对象时的一些清理工做,如释放分配给对象的内存空间等。析构函数和构造函数名字相同,但在前面加一个波浪号(~),析构函数没有参数也没有返回值,并且不能重载。所以一个类中只有一个析构函数。当撤销对象时,编译系统会自动调用析构函数。
拷贝构造函数,它的做用是在创建一个新对象时,使用一个已经存在的对象去初始化这个新对象,如point p1(p2)或point p1=p2;拷贝构造函数只有一个参数,而且是同类对象的引用,每一个类都必须有一个拷贝构造函数。
由于成员函数代码是同类全部对象共用,为了使成员函数辨别出当前调用本身的是哪一个对象,c++引入了自引用指针this,每当建立一个对象,系统就把this指针指向该对象,当调用成员函数时,系统把this指针做为一个隐含参数传递给该函数。
对象中的数据成员有本身独立的存储空间,互不相干,但有时但愿不一样的对象能够共享一个或几个数据成员,实现同类的不一样对象间数据共享,因而有了静态成员的概念。不管创建多少类的对象,都只有一份静态数据成员的拷贝,从而实现同类的不一样对象间的数据共享,静态成员属于类,因此能够用类直接访问。静态成员函数不是为了对象间的沟通,而是为了处理静态数据成员。静态成员函数没有this指针,因此通常不访问非静态成员,若是要访问非静态成员,则需显式的经过对象名.非静态成员名来访问。
有了静态成员来实现同类不一样对象间的数据共享,一样为了实现类间的数据共享,c++引入了友元这一律念。友元是一扇通向私有成员的后门。
一个类的友元函数不是该类的成员,它能够是不属于任何类的非成员函数,也能够是另外一个类的成员函数。定义时需在友元函数前添加关键字friend。一个类的友元函数能够访问该类的私有成员,但它毕竟不是该类成员,因此在定义和调用该类时没必要像成员函数那样在函数名前加上“类名::”。它也没有this指针,须要显式的经过“对象名.数据成员”才能访问数据成员。成员函数只能访问它所属的类,但一个函数若是被定义为多个类的友元函数,那它能够访问这些类的全部数据。使用友元函数时必需要慎重。
能够将一个类好比y定义为另外一个类x的友元类,那么y类中的全部成员函数都是x类的友元函数。
继承就是从先辈处获得属性和行为特征,较好的解决了代码重用的问题。默认为私有继承,还有公有继承、保护继承。基类的构造函数和析构函数不能被继承,当建立派生类对象时,先调用基类的构造函数,在调用派生类的构造函数,撤销派生类的对象时,顺序相反。在没有虚函数的状况下,若是派生类中定义了与基类成员同名的成员,称派生类成员覆盖了基类成员,如要在派生类中使用基类同名成员,必须使用“基类名::同名成员”的方式显式指定,若是在对象中调用就用“对象名.基类名::同名成员”。
当一个派生类有多个基类时,成为多继承。多继承要注意构造函数的书写,同时多继承带来一个问题:当派生类y有两个基类a和b,同时a和b有一个共同的基类c,这样y就会继承两个c的拷贝,当要访问c的成员时,必须显式的指定是a仍是b的成员,以避免产生二义性,为了解决这个问题,c++引入虚基类的概念。上例中能够把c声明为a和b的虚基类,即:class a:virtual 继承方式 c和class b:virtual 继承方式 c这样从a和b继承的y只会继承c一次。
不一样数据类型数据之间的自动转换和赋值,称为赋值兼容。基类和派生类对象之间也存有赋值兼容关系:在基类对象可使用的地方均可以用派生类的对象来替代。派生类对象能够赋值给基类对象,指向基类对象的指针能够指向基类的公有派生类,但不能指向私有派生类。
所谓多态性就是不一样对象收到相同的消息,产生不一样的动做。连编是把函数名和函数体的程序代码链接(联系)在一块儿的过程。静态连编在编译阶段就完成了,函数调用速度快,效率高,但缺少灵活性,动态连编在运行阶段完成,在程序运行时才去肯定调用哪一个函数,下降了程序运行效率但加强了灵活性。c++是编译型语言,仍采用静态连编,好在c++引入了“虚函数”从而实现了静态连编和动态连编相结合。虚函数是基类中的成员函数,前面加有关键字virtual,并在派生类中被重载,在派生类中被从新定义时其函数原型包括返回类型、函数名、参数个数、参数类型的顺序,都必须和基类中的原型彻底相同。
虚函数使用的基础是赋值兼容规则,而赋值兼容规则成立的前提条件是派生类从其基类公有派生,因此要想经过定义虚函数来实现动态多态性派生类就必须是从基类公有派生。内联函数不能是虚函数,由于内联函数不能在运行中动态肯定其位置,因此即便虚函数在类的内部定义。编译时仍将它当作非内联的。
基类每每表示一种抽象的概念,此时在基类中预留一个函数名,具体功能留给派生类根据须要去定义,这样一个虚函数就成为纯虚函数,格式以下:virtual 返回类型 函数名(参数表)=0;含有纯虚函数的类称为抽象类。抽象类的目的就是用它去创建派生类,抽象类不能实例化为对象。也不容许从非抽象类派生出抽象类,抽象类也不能作函数参数类型、返回类型或显式转换的类型。
运算符的重载,须要写一个运算符函数,好比要重载”+”号,就要写一个名为operator+的函数。运算符重载函数有两种形式,一种是定义为它要操做的类的成员函数,另外一种是定义为该类的友元函数。友元运算符重载函数以下:
class x{
……
friend 返回类型 operator运算符(形参表);
……
}
注意友元函数不是类x的成员不能直接访问x的成员,要显式指定“x.成员名”也没有this指针。并非全部的运算符均可以定义为友元运算符重载函数,如赋值运算符“=”,下标运算符“[]”,函数调用运算符“()”等。
对于x=x1+x2;c++解释为x=operator+(x1,x2);
成员运算符重载函数格式以下:
class x{
……
返回类型 operator运算符(形参表);
……
}
由于成员函数能够在函数体内直接访问类x的成员,并且有this指针隐含的指向当前对象,因此对于双目运算符,只需一个形参就能够了。
对于x=x1+x2;c++解释为x=x1.operator+(x2);
通常来讲,双目运算符能够被重载为友元函数活成员函数,但也有例外只能用友元函数,好比一个类的对象和一个整数或其余类对象相加的成员函数:
若是是x和整数i相加 x=x1+i;是正确的,由于c++解释为x=x1.operator+(i);
但x=i+x1;却出错,由于c++解释为x=i.operator+(x1);可是i是整数,并无成员函数operator+因此编译出错。
为了解决这一问题,只能定义两个友元函数:
class x{
……
friend 返回类型 operator运算符(x& x1,int i);
friend 返回类型 operator运算符(int i, x& x1);
……
}
利用函数重载来解决运算符两边操做数交换的问题。
对于“++”和“--”等分前缀用法后缀用法的运算符用“int”区分,没有int是前缀用法,有是后缀用法。
class x{
……
friend 返回类型 operator运算符(x& x1);//前缀
friend 返回类型 operator运算符( x& x1,int);//后缀
……
}
为了解决“浅拷贝”带来的“指针悬挂”问题,能够重载赋值运算符”=”,引入深拷贝。
类型转换分为标准类型(如int,float,double,char等)间的转换和类类型和标准类型间的转换。准类型间的转换c++已经自带了方法转换,不需用户在写方法。
类类型和标准类型间的转换有两种方法一、经过转换构造函数进行类型转换二、经过类型转换函数进行类型转换。
在程序设计的过程当中常常出现这样的状况:两个或多个函数的函数体彻底相同,差异仅在于它们的参数类型不一样,为了提升代码的可重用性和可维护性,c++提出了模板概念。
在c语言中能够用宏定义#define,可是宏定义避开了类型检查,容易出错。
模板能够实现参数类型参数化,即把数据类型定义为参数,从而实现代码重用。模板分为函数模板和类模板,他们分别用来创建模板函数和模板类。
函数模板是创建一个通用函数,其函数返回类型和参数类型不具体指定,用一个虚拟的类型来表明,这个通用函数就是函数模板,系统调用函数时根据实参的类型取代模板中虚拟类型。
格式以下:
template <typename 类型参数>
返回类型 函数名(模板形参表)
{
函数体
}
或者
template <class 类型参数>
返回类型 函数名(模板形参表)
{
函数体
}
通常为了与类声明中的class区分,通常用第一种格式,c++中的类型参数通常是t、type等。,typename和class用来表名后面的参数是一个虚拟的类型名。函数模板须要实例化一个模板函数才能调用,当编译系统发现一个函数调用
函数名(模板实参表)
就会根据模板实参表中的类型生成一个函数即模板函数。模板函数中的函数体与函数模板函数体相同。函数模板能够和同名的非模板函数重载,调用顺序是先寻找一个参数彻底匹配的非模板函数,若是有就调用没有就寻找函数模板将其实例化,如实例化模板函数成功就调用它。
对于类的声明也能够采用相似的方法,使用类模板能够简化那些功能相同而数据类型不一样的类的声明。格式以下:
template <typename 类型参数>
class 类名{
类成员声明
};
或
template <class 类型参数>
class 类名{
类成员声明
};
类模板定义对象的格式是:
类名<数据实际类型> 对象名(参数表);
c++支持c语言的输入输出系统以外,还定义了一套面向对象的输入输出系统。“流”是数据从一个源留到目的的抽象,负责数据的生产者和消费者之间创建联系并管理数据的流动。i/o流类库中各类类的声明包含在相应的头文件中如iostream、fstream、strstream、iomanip。
类ios是流的基类是抽象类。流类定义的对象称为流对象,c++中有几个预约义好的流对象:标准输入流对象cin、标准输出流对象cout、非缓冲型标准出错流对象cerr和缓冲型标准出错流对象clog。
cout中经常使用的成员函数:cout.put(a)输出一个字符a;
cin中经常使用的成员函数:cin.get(ch)功能是从输入流读取一个字符(包括空白符)赋给字符型变量ch;cin.getline(字符数组,字符个数n,终止标识符)或cin.getline(字符指针,字符个数n,终止标识符)功能是从输入流读取n-1个字符,若是提早读到终止标识符就提早结束最后总要插入一个字符串结束标志’\n’。cin.ignore(n,终止字符)功能是跳过输入流中的n个(默认1个)字符或遇到指定的终止字符(默认是eof)提早结束跳跃。
流基类ios中定义了一些进行输入输出格式控制的成员函数,查看书籍,除此以外c++提供了另外一种输入输出格式控制的方法,称为操纵符,查阅书籍,用户也能够自定义操纵符。格式以下:
输出流:
ostream &操纵符名 (ostream &stream)
{
自定义代码
return stream;
}
输入流:
istream &操纵符名 (istream &stream)
{
自定义代码
return stream;
}
文件流用来处理外存文件,根据文件中数据的组织形式,文件可分为两类:文本文件和二进制文件。文本文件又称ASCii文件,一个字节存放一个ASCII代码表明一个字符,二进制文件则是内存中的存储形式原样写到外存中造成的文件,好比整数100,在文本文件中是以‘1’、‘0’、‘0’三个字符的ASCII的代码存放的,占3个字节,而在二进制文件中就是100的二进制形式01100100存放的,占一个字节。
C++进行文件操做的通常步骤:一、为要进行操做的文件创建一个文件流对象,二、打开文件,若是不存在就建立该文件,三、进行读写操做,四、关闭文件。用到的类ifsteam(用于文件输入)、ofsteam(文件输出)、fsteam(文件输入输出)。
成员函数:
文件流对象.open(文件名,使用方式):以特定方式打开文件
文件流对象.open():关闭文件
文件流对象<<数据:写入文件
文件流对象>>变量:读取数据
文件流对象.read(char *buf,int len):读取len个字符到buf数组
文件流对象.write(const char *buf,int len):将buf数组中len个字符写入文件。
文件流对象.eof():检测是否到达文件尾。
随机读写函数:看书籍。
命名空间是由程序设计者命名的一个内存区域,用来处理程序中同名冲突问题。定义格式以下:
Namespace 空间名
{
代码
}
C语言中没有命名空间,若是C++使用的带扩展名.h的头文件,没必要使用命名空间。若是C++使用的不带扩展名.h的头文件就要指定头文件所在的命名空间。
程序中的常见错误分为:编译时的错误和运行时的错误。编译时的错误主要是语法错误,运行过程的错误统称为异常,对异常的处理就是异常处理。
C++中处理异常的办法是:若是执行一个函数出现异常,能够不在本函数处理而是甩给上一级也就是函数的调用者,一直能够逐级上传一直到最高级,若是最高级也没法处理,系统会调用系统函数terminate(),有它调用abort终止程序。
C++异常处理机制有检查、抛出和捕获三个部分:try(检查)、catch(捕获)、throw(抛出)
格式以下:
Throw 表达式:
Int i;
Throw i;由于i是整型变量,因此throw抛出的是整型异常;
Throw抛出的异常会由catch捕获。
Try
{
被检查的语句
}
Catch(异常类型声明1)
{
进行异常处理的语句1
}
Catch(异常类型声明2)
{
进行异常处理的语句2
}
……
Try和catch必须配套使用。
本书主要内容就是这些。