*********************************************************************

一.C++的简介
1.1发展历史
80年代 贝尔实验室
83 正式命名 C++
87 GNU 制定了C++标准
92 微软和IBM 制定了C++标准
98 ANSI/ISO 制定了C++98 标准
03 ISO 推出了 C++03
11 ISO 推出了C++11/C++0x

使用g++ ***.cpp -std=c++0x

1.2 C++和C的关系
C++是建立在C的基础上的
C++对类型的检查更加严格

C++扩展了C语言
面向对象编程(以类的方式来组织代码)
运算符重载(一种函数的特殊表现形式)
支持异常(一种新的错误处理方式)
泛型和模版(类型通用编程)

二.第一个C++程序
2.1 源文件
推荐以.cpp结尾,也可以是.C .cxx .c++ 等

2.2头文件
标准的C++头文件基本上没有.h
头文件在/usr/include/c++ 下面

在C++程序中使用标准C的头文件采用去尾加头,例如:#include<cstdio>
#include<cstring>

在C++程序中使用系统C的头文件时,原样导入,例如:#include<unistd.h>

在C++程序中使用自定义的头文件时,原样导入,#include "date.h"

2.3 使用库函数 正常使用
C的库函数 输入输出需要指定输出格式,C++的cout,cin不需要,他们可以自动识别格式。

2.4 编译器
g++,可以使用gcc,但需要指定链接库,-lstdc++;
编译选项完全和gcc相同
-o 指定输出文件名
-c 编译
-E 预处理
-S 生成汇编
-l 指定库名
-L 指定库文件的位置
-I 指定头文件的位置
-On 优化
-g 生成GDB调试信息

2.5 using namespace std;
使用命名空间std;


三.命名空间 namespace

3.1 概念
把一组相关的类型 函数 变量等组织到一起 然后为这个逻辑结构起一个逻辑名。

3.2 作用
便于逻辑上划分模块
避免命名冲突

3.3语法
namespace 空间名{
//正常程序的书写
}

3.4如何使用命名空间

3.4.1 使用空间名::数据

3.4.2 使用using声明
using 空间名::数据名;

3.4.3 使用命名空间指令
using namespace 空间名;

3.5 命名空间的嵌套
namespace 空间名1{
namespace 空间名2{

}
}

3.6 无名命名空间
如果一些数据没有定义在任何命名空间中,则这写数据会被自动定义在无名命名空间。
访问方式:::数据名

namespace {

}

 

四.C++中的结构 联合 枚举

4.1 结构体
定义的语法完全和C相同
不同点:
在表达类型时,可以省略struct关键字。结构体中可以定义函数,没有定义任何成员的结构体在C++中大小是1,C语言中大小是0


4.2 联合体
定义的语法完全和C相同,
不同点:
在表达类型的时候可以省略union关键字,C++中支持匿名联合

4.3 枚举
定义的语法和C相同
不同点:
表达类型时,可以省略enum关键字
枚举的本质是一个小范围的整数,所以枚举变量的值可以赋给整数变量。
但在C++中,不能把整数变量的值赋值给枚举变量,这里体现了C++对类型检查的严格。

 

五.C++中的bool类型
C++本身就直接支持bool类型,而C语言使用bool类型需要导入一个头文件#include<stdbool.h>

bool类型的值只有true和false,但bool类型的变量可赋任何值 只有四个代表假其他都是真。
false 0 NULL '\0'

当输出布尔类型数据时,默认把它作为整数处理,真就是1,假就是0.


六.C++中的符号替换
1. && and
2. || or
3. & bitand
4. # %:
5. { <%


七.C++中的函数和C函数的不同

7.1 C++中的函数无参参数列表严格匹配 无参代表没有任何参数,void型参数依然可用。
void testa();

7.2不再支持C语言中的隐式声明,函数调用之前要么进行前置定义,要么就行前置声明。

7.3 函数的返回值类型不能省略,不再支持C中默认返回int类型的机制。主函数可以省略。


八. 函数重载 overload
8.1 概念
在同一个作用域中使用 函数名相同 参数列表不同的函数是允许的,这叫函数重载。
所谓参数列表不同:指参数的类型不同或者参数的个数不同或者参数的顺序不同。
8.2 定义一个函数指针 使用函数指针调用上面例子中的第二个函数。

 

***********************************************************************
一.函数重载

1.1函数重载的原理
在生成函数的调用名时,C++语言不单要考虑函数名,还要考虑参数列表。而C语言只考虑函数名,所以不能重载。

1.2函数重载引入的问题

跨编译器调用问题
如果让C++程序调用C语言生成的库,C++在调用函数名的时候会在底层查询函数名,但是C生成的函数名和C++是不同的,所以会产生错误。
使用extern "C" 来指定按照C语言的方式来生成调用的函数名。

二.函数参数的哑元
2.1概念
如果一个函数的参数只有类型没有形参名,则称之为哑元。
2.2作用
在C语言中让无参参数列表更加严格,在C++中明确指定无参参数列表。
int foo(void);

保持函数的向前兼容的特性。

区分成员函数


三.函数参数的默认值
3.1 概念
一个函数的参数可以设计一个默认的值,调用函数时不给这个函数的参数传参,则使用默认的值,如果传入参数值会替代掉默认的值。

3.2 注意
参数的默认值要遵循靠右原则,一个参数有默认值 则这个参数右边的所有参数都必须有默认值。
默认值不要和重载形成调用冲突,
printNum(int x,int y=1);
printNum(int x)这样写重载时,没办法使用默认值,因为系统不知道你调用哪一个。
当函数的声明和实现分开时,要在声明中指定 在实现中不能再指定默认值。

 

四. 内联函数 inline
4.1 带参的宏 宏函数
define MAX(x,y) (x)>(y)?(x):(y)

4.2 内联函数
inline 就是请求编译器在编译时 把函数的二进制代码赋值到调用位置 这样可以减少函数调用的栈开销。以提高程序的运行速度。


4.3内联的注意事项
小函数频繁调用适合使用内联函数
而大函数 稀少调用 不适合使用内联函数
递归函数不能实现内联
内联中的inline只是一个请求,能否实现看编译器。


五.C++中的动态内存分配

5.1 new delete
new负责堆内存的申请,类型 *指针名=new 类型名;
new负责堆内存的申请,类型 *指针名=new 类型名(值);这样写可以赋初值。

delete负责堆内存的释放,delete 指针名;

5.2 当需要分配多个内存空间的时候,使用new[],delete[]
类型 *指针名=new 类型[n];
释放这块内存 delete [] 指针名

5.3 使用new[] 来申请5个整数对应的堆内存 使用指针给这块空间赋值。赋值成9 5 2 7 6 ,然后使用循环取得这块空间中对应的值,最后释放这块空间

5.4定位内存分配
char data[100];
int *pdata=new (data)int[25];
pdata不同delete[]去释放,因为此时他指向的是栈内存

 

 

六.引用(reference)
6.1 引用就是一个别名

6.2 类型 &引用名=被引用变量; //引用声明的时候必须初始化
引用就是一个对象的别名,内存存储只有一份物理存储,所以引用是不占内存的。不管修改原变量还是引用变量,另外的一个都会随之改变。

引用一旦初始化之后,就终身为这个变量服务,在引用的生命期内不能再引用别的对象


6.3 引用的应用
6.3.1 引用类型的参数
写一个程序,设计两个整数参数 完成两个整数值的交换。

6.3.2 const引用型的参数
const 类型& 变量名=值;

6.3.3 引用类型作为返回值
在C语言中,非指针类型的函数返回值,只能作为右值,不能作为左值。
C++中如果一个函数返回引用类型,则代表这个函数的返回值可以作为左值。

不能返回局部变量的引用,能返回static变量 全局变量 堆内存变量 引用型参数 成员变量的引用

6.4 引用的底层实现
引用的底层实现是指针

const在*前面 代表不能通过指针修改对应的内存值,但是可以改变指针的指向,const在*后面,基本上实现了一个引用的效果。

所以引用的底层实现是通过后者实现的。即 int *const rx=&x;

 


七.C++中的类型转换运算符

7.1 static_cast<类型>(变量)
在某一个方向上,可以做自动(隐式)类型转换
void *pv 和其他指针

7.2 dynamic_cast<类型>(变量)
适用在具有多态性的父子类之间

7.3 const_cast<类型>(变量)
专业去const的
const修饰的变量 在C++编译器中会进行优化形式的替换 如果想解除这种替换优化,可以加volatile修饰变量。

7.4 reinterpret_cast<类型>(变量)
最接近强制类型转化的
如把整数变成指针,把指针变量整数。

 


******************************************************************

一.C++之父给C程序员的建议
1. 尽量的少使用宏
使用const 或者枚举来表达常量值
使用inline减少函数调用开销
使用泛型和模版来刻画一组函数或类型

2.使用命名空间减少命名冲突

3.变量随时用随时定义,以保证它的初始化

4.尽量的避免强制类型转换 因为类型转换一般是程序设计的问题,转换是错误的指示器,非要转换就使用四个转换运算符

5.尽量减少C字符串的使用,string类型可以做的更好

6.尽量的少使用malloc或free,因为new和delete会做的更好。

7.逐渐建立面向对象的思想

 

二.面向对象编程

2.1 什么是对象
一切的事物都可以使用对象的形式进行描述或者刻画。
程序就是一组对象组成的 通过发消息来完成通知相互做什么。
对象都是由其他的对象组成的。 最终对象是由基本类型构成的。
每一个对象都对应一个类型。
相同类型的对象 都可以接受相同的消息和发出相同的消息。

2.2如何来刻画对象 分类
特征:
/* 成员变量 */
string name;
int age;
string color;
行为:
/* 成员函数 */
void show();

现实世界 抽象到 计算机世界

2.3 如何描述这些设计好的类型

2.3.1 使用struct来进行描述
刻画汽车类

特征:
string name;
string cno;
int speed;
string color;

行为:
void show();
void start();
void run(int speed);
void stop();

2.3.2 使用结构体 刻画一个时间类

特征:
int hour;
int min;
int sec;

行为:
/* 设置时间 */
void setTime(int h=0,int m=0,int s=0)
/* 显示时间 */
void show();
/* 走一秒 */
void dida();
/* 运行 不断的显示 不断的走秒 */
void run();

2.3.3 使用class描述类别

关键字不同,权限默认不同,结构体默认权限是公开的,public
class中的默认权限都是私有的,private
公开的数据,类内外都可以直接使用,而私有的数据只能直接在类内使用。

权限的修饰 从第一个权限开始直到下一个权限出现为止。
public:
private:
protected:

2.3.4 使用class来描述一个日期类
特征:私有的
int year;
int month;
int day;
行为:公开的
设置日期 默认值 2014 1 1
void setDate(int y,int m,int d);
显示日期 格式yyyy-mm-dd
void show();
创建两个日期对象 显示他们的数据


三.构造函数
3.1 概念
一个在构建对象时,自动调用的函数
函数名和类名相同,没有返回值类型,构建一个对象,自动调用一次。
使用构造函数目的是初始化对象。
一个类如果没有提供构造函数,则编译器会自动提供一个无参的构造函数。但一旦提供构造函数,则编译器会回收默认的构造函数。

3.2 一个对象的创建过程
根据对象的类型分配内存大小,
处理对象的成员变量
成员变量如果是基本类型 则什么也不做
成员变量如果是类类型 则构建这个成员
调用这个类型的构造函数


3.3 构造函数的使用
3.3.1
使用构造函数的参数默认值来简化构造函数的个数。
但不要和重载形成冲突

3.3.2 初始化列表
在构造函数调用之前去执行。
处理const类型的成员或者引用类型的成员初始化列表是不二选择。
初始化列表的位置是在构造函数之后。 实现体之前,以冒号开头。
可以处理普通成员,还可以对成员变量和参数重名时进行区分。
class A
{
const int x;
int& y;
public:
A(int px=0,int py=1):x(px),y(*(new int (py)))
{
y=1;
}
};


四.在实际开发中,头文件和实现文件是分离的。
4.1 书写头文件
条件编译 防止头文件重复包含
函数声明(函数实现体) //头文件中是可以实现函数的
类型定义
变量的声明

4.2 书写实现文件

导入头文件
去掉类型定义,成员变量定义 权限
类中的每个函数需要在函数名前加类名::
函数的默认值去掉
4.3写测试文件


六.指针的引用的区别
引用的底层是用指针来实现的。
之前很多指针实现的效果可以使用引用来实现
一级指针作为函数参数可以修改外部的值,引用也可以完成。
二级指针作为函数参数可以修改外部的地址,可以使用指针的引用,int*&

指针作为函数的返回值引用可以完成,

6.2区别
1.引用定义时必须进行初始化。指针不是必须要初始化的。
2.引用就是一个别名,而指针是一个实体变量。指针大小一定是4,而本质上引用对应的内存只有一份。
3.有指针的指针,即二级指针。但没有引用的引用。
4.但是有指针的引用 没有引用的指针。
5.有指针的数组,但没有引用的数组。
6.但有数组的引用

 

**********************************************************************
一.const对象和const函数
1.1 概念
const对象就是加了const修饰对象
const A a;
对于这样的const对象,要么初始化,要么提供无参构造

const函数
一个成员函数 如果加了const修饰,则这个函数称之为const函数。
const函数和同名的非const函数可以形成重载

1.2关系
非const对象优先调用非const函数,没有非const函数则调用const函数。const对象只能调用const函数

const函数只能读取普通成员变量,不能写。并且不能调用非const函数,只能调用const函数。

如果非要在const函数中修改成员变量,则在成员变量上加mutable修饰即可。


二.析构函数
2.1 在对象销毁之前,自动调用的函数
和类名相同,函数名前有一个 ~ ,负责内存的释放和资源的处理

只有需要处理堆内存和释放资源时,才需要自定义析构函数

三.C++中的new delete 比malloc free多做写什么?

3.1 new比malloc多做了三件事
如果对象成员的类型是类类型 会自动构建成员
自动调用构造函数
自动处理类型转换

3.2 delete比free多调用了一次析构函数


四.this 指针
4.1 指向当前对象的指针
在构造函数中 this指针代表正在被构建的对象。
成员函数中 this代表调用这个成员函数的对象的地。


4.2 this 指针的应用
用来区分成员变量和参数名
this指针作为函数的参数 或者参数的值相关
this作为函数的返回值或者返回值相关

五. 拷贝构造函数

5.1 概念
以复制形式来创建对象的构造函数
A(const A& a)
{

}

5.2 拷贝构造函数的调用时机
用一个已经存在的对象 以复制形式创建另外一个对象。(不提供拷贝构造函数,则系统会默认提供一个拷贝构造函数,这个函数会完成数据的逐字节拷贝) 这种拷贝被成为浅拷贝*********
把对象传入非引用类型函数参数时

5.3 什么时候需要自定义拷贝构造函数
浅拷贝只能完成基本数据的拷贝,一些不能共享的数据浅拷贝就会引入问题。


5.4 内存那点事
构造函数 申请堆内存
析构函数 释放堆内存
拷贝构造函数 处理内存对立性问题
赋值运算 处理内存泄露问题和内存独立性问题


六. 静态成员
6.1 静态数据
用来处理数据共享问题

6.2 静态成员变量
类型级别共享的变量
静态成员变量必须在类外进行初始化。静态成员变量类型 类名::静态成员变量名;这样写基本类型赋值成0,类类型调用无参构造。
静态数据就是可以通过类型名直接访问的全局变量,只不过受权限的控制而已。

6.3 静态成员函数
受类名,作用域 和权限控制的全局函数 可以通过类型名直接访问。
静态成员函数中 没有this指针 所以不能直接访问非静态成员 直接访问静态成员

 

思考:如果实现一个单例模式?
在整个应用程序中,只有一个这种类型的对象。
权限控制 构造函数 拷贝构造函数 静态成员 静态成员函数 引用


******************************************************************

一. 成员指针
1.1 指向普通的成员变量的指针

1.1.1 语法
struct Date{
int year;
int month;
int day;
};
/* 定义成员变量指针 */
int Date::*pmem;
/* 赋值 */
pmem=&Date::month;
/* 通过成员指针取得变量中的值 解引用 */
Date date;
date.*pmem;
Date *pb=new Date();
pb->*pmem;

1.1.3 成员变量指针的本质是什么?
本质就是记录指针在对象首地址中的偏移量

1.2 指向成员函数的指针

1.2.1 语法
struct Date{
int year;
int month;
int day;
int getYear()
{
return year;
}
int getMonth()
{
return month;
}
};

/* 成员函数指针的定义 */
int (Date::*pmem)();
/* 成员函数指针的赋值 */
pmem=&Date::getMonth;
/* 解引用 */
Date date;
(date.*pmem)();
Date *pb=new Date();
(pb->*pmem)();

二.运算符重载
2.1 本质
一种函数的特殊表现形式
分数类
特征:
分子,分母
行为:
构造函数
显示分数

2.2 编译器对运算符的翻译规则

fa+fb
L#R 先去L对象对应的类型中 找一个成员函数 叫operator#(R) 如果找不到就去全局函数中找一个全局函数 叫operator#(L,R)
最后综合选择最优的函数掉用


2.4 成员函数 静态成员函数 友元函数
访问类的私有成员
受类名和类的权限控制
必须通过对象访问

成员函数需要遵守上面的三条,静态函数只需要遵守前两条,友元函数只遵守第一条。


2.5 特殊的二元运算符 << , >>
L#R 先去L(cout)对象对应的类型(ostream&)找一个成员函数 叫operator<<(R) 如果找不到就去全局找一个全局函数 叫operator<<(L,R)

流类型不能加const修饰,
流类型对象不能拷贝


2.6 写一个整数的包装类,然后可以完成两个整数的相加减的运算符支持。还要支持这个对象的输入和输出。

单参构造原则 可以把一个参数的构造函数中对应的类型变成当前对象类型。


2.7 一元运算服符的重载

~!- ++ --
#R 先去R对应的类型中 找一个成员函数 叫operator#() 如果没有就去全局找一个全局函数 叫operator#(R)

 

 

 

*****************************************************************

一.运算符重载的限制

1.1不能重载的运算符
:: 作用域运算符
. 成员访问运算符
.* 成员指针解引用
sizeof 求类型或者对象对应的大小。
? : 三目运算符不能重载
typeid 获取类型信息的

1.2 不能对基本类型的数据进行运算符重载,至少有一个是类类型

1.3 只能对已有的运算符进行重载,不能发明运算符。

1.4 不能改变运算符的运算特性

1.5 有些运算符只能以成员形式进行重载。
= 赋值运算符
[] 下标访问运算符
()圆括号运算符 函数对象,处理类型转换
-> * 指针操作运算符

二.只能是成员的运算符举例
2.1自定义数组
= [] 的使用

内存那点事:
构造函数 分配内存
析构函数 释放堆内存
拷贝构造函数 处理内存独立性问题
赋值运算符 处理内存独立性和内存泄露问题。


2.2 ()圆括号运算符的重载

函数对象 可以像函数一样使用的对象
为了实现这种功能,可以重载operator()(参数列表);

可以完成当前对象类型转换成某一个类型
operator 转换成的类型()
{

}

把某一个类型 可以自动转换成当前对象类型 使用单参构造。如果要防止这种隐式单参转换 可以在单参构造函数上加 explicit。


2.3 -> * 的重载
把一个不是指针的类型当作指针类型来使用

智能指针

 

三. new delete运算符的重载

这两个运算符的原型
void* operator new(size_t size);
void operator delete(void* ptr);

 

四.面向对象变成的三大特征

封装:

继承:

多态:


五.封装
5.1 概念
该公开的数据就public,该隐藏细节的数据就private。
5.2 作用
便于分工和划分模块
防止代码不必要的扩展


六.继承
6.1 目的
代码复用
扩展

6.2 举例

Animal
特征:
string name;
int age;
功能:
void show();
void run();

Dog
特征:
string color;
功能:
void dogfun();

6.3 语法
class 子类名:继承类型 父类名
{

};


6.4 继承VS组合
继承是一种 子类 is a 父类的关系
组合关系
Car 汽车类
Raido 收音机类
Car has a Radio

6.5 继承的方式
公开继承 class 子类:public 父类
私有继承 class 子类:private 父类
保护继承 class 子类:protected 父类

6.6 公开继承
公开继承下 父类的数据权限 到了子类之后的变化。
父类的公开数据到子类之后 是公开的
父类的保护数据到子类之后 是保护的
父类的私有数据到子类之后 是隐藏的。

**********************************************************************

一.私有继承
私有继承下 父类数据权限到子类之后的变化:
父类公开的数据到子类中是私有的,父类保护数据到子类中是私有的,父类中私有的数据到子类中是隐藏的。

二.保护继承
保护继承下 父类数据权限到子类之后的变化
父类公开的数据 到子类中是保护的
父类保护的数据 到子类中是保护的
父类中私有数据 到子类中是隐藏的

所谓的继承方式 就是父类能给子类的最高访问权限
父类中私有的数据 到子类中是隐藏的

三.在继承中构建子类对象时,父类构造和子类构造的调用顺序

构建子类对象时,一定会调用父类的构造函数,子类默认调用父类的无参构造
子类可以通过初始化列表 指定调用父类的构造函数

析构的调用顺序一定和构造函数调用顺序相反


四.继承中构建子类对象时,父类拷贝构造和子类拷贝构造的调用顺序问题。

子类触发拷贝构造时,默认一定会先调用父类的拷贝构造,再调用自己的拷贝构造。
但一旦子类提供了拷贝构造函数,则不再默认调用父类的拷贝构造。需要人为指定调用


五.继承中赋值运算符的调用
子类触发赋值运算符时,默认一定会先调用父类的赋值运算符,再调用自己的赋值运算符。
但一旦子类提供了赋值运算符,则不再默认调用父类的赋值运算符。需要人为指定调用。

使用父类名::operator=(子类对象);即可调用父类的赋值运算符函数。


六.名字隐藏
当子类中 提供和 父类同名的数据时,会把父类的数据隐藏掉 这种机制叫名字隐藏。

使用父类名::数据名 来调用父类的同名函数


七.多继承

7.1 概念
一个类可以有多个直接父类

7.3 语法
class 子类名:public 父类名1,public 父类名2,public 父类名3
{

};

父类构造函数的调用顺序和继承顺序一致.

子类可以直接调用不冲突的数据
如果父类中 提供了同名的数据,则子类就会出现冲突,可以使用名字隐藏机制避免冲突。


7.5 防止数据冲突的第二种手段
(1)把父类的共同部分 抽取到更高层类中
(2)采用虚继承的方式继承更高层的类
(3)再让子类继承父类
孙子类可以直接访问高层类

 

八.虚函数
8.1 概念
非静态的成员函数上加virtual 关键字

 

九.函数重写(函数覆盖)overwrite
9.1 概念
在子类中,提供一个和父类同名的虚函数 要求返回值 函数名 参数列表都必须相同。

9.2 什么叫函数重载 名字隐藏 函数重写
函数重载:同一个作用域中,函数名相同,参数列表不同的函数构成重载关系
名字隐藏:子类中提供了和父类同名的数据叫名字隐藏
函数重写:子类中提供了和父类同名的虚函数叫函数重写。

 


十.多态

10.1 概念
当父类型的指针(引用) 指向(引用)子类对象时,如果调用父类中的虚函数并且子类重写了这个虚函数 则调用的表现是子类的表现。

继承是构成多态的基础,
虚函数是构成多态的关键
函数重写(函数覆盖)是多态的必备条件 


***************************************************************************

一.多态(类型通用,便于扩展)
1.1 多态的使用
父类型 做函数参数
父类型 做函数的返回值

1.2 多态的实现

运行时绑定(动态绑定):
在运行时确定函数的入口
当父类对象指针 指向子类对象时 如果调用虚函数 则编译器不会立即绑定
调用的函数地址

编译时绑定:在编译期确定函数的入口


1.3 多态的底层实现(如何实现动态绑定)

虚表指针
如果一个类型中定义了虚函数 则用这个类型创建的对象会多出一个指针类型的成员,这个指针成员指向虚函数表。
一个类型中 只有一张虚函数表,这个类型的对象那个共享虚函数表。

一个父类指针指向一个对象时,先根据对象定位到虚函数表的地址,然后根据调用的函数名,取得调用的函数地址。这个函数地址对应什么样的函数就做什么样的表现。


二.动态类型识别
可以把父类指针指向的子类对象类型识别出来 进而恢复子对象的个性。

2.1 使用dynamic_cast<转换成的类型>(对象),尝试把一个对象转换一个类型 如果转换成功则返回非空指针。如果返回NULL,则代表转换失败。

2.2 使用typeid进行类型识别
typeid会返回一个对象叫type_info
name() 类型的名字
== 判断两个type_info对象是否相等 相等就代表类型相同
!= 判断两个type_info对象是否不相等


三.抽象类
3.1 概念
如果一个类无法实例化 则这个类是抽象类
抽象类型除了不能实例化 其他和正常的类型没有任何区别。

3.2 如何实现抽象类型
纯虚函数
class A
{
public:
virtual void show()=0;
};
子类继承抽象类,需要实现纯虚函数 否则子类也自动成为抽象类。

如果除构造 析构函数之外 所有的函数都是纯虚函数 则这个类称之为纯抽象类。(接口)

四.虚析构函数
当父类对象的指针指向子类对象时,释放这个指针对应的内存,则只会调用父类对应的析构函数,子类析构函数行为未定义
Animal *pa=new Dog();
delete pa;只会调用父类的析构函数
只要把父类中的析构函数 设置成虚析构函数 则释放父类型指针对应的子类对象,则会调用子类的析构函数。进而触发父类析构调用。


五.内部类
class A
{
public:
void show()
{

}
class B
{

};
};

 

六.C++中的异常处理
6.1 什么是异常
一种错误的表达形式
C中是使用返回值代表错误,不能的返回值代表不同的问题。

6.2 如何抛出异常
throw 异常对象;
如何抛出的异常不做任何的处理 则程序默认调用terminate函数终止进程。

6.3 捕获异常 处理异常
try
{
可能会出现异常的代码
}
catch(异常类型 e)
{
}
catch(异常类型 e)
{
}

6.4 异常的说明
void foo(); 这代表可能会抛出任何异常
void foo() throw();这代表不抛出任何异常
如果抛出异常 则异常不可捕获
void foo() throw(异常类型1,异常类型2,异常类型3);

6.5 系统定义的异常
基本类型携带的信息比较少,所以可以使用系统定义好的异常

触发系统异常 可以使用catch 捕获相应的预定义好的系统异常类别 进而进行相应的处理。

6.6 用户自定义异常
(1)定义异常
根据程序中可能会出现的问题 使用类把这些问题描述清楚。
(2)根据条件抛出异常
if()
{ throw 异常 }
else
{ throw 异常 }
(3)捕获异常
try
{
可能抛出异常的代码;
}catch(异常类型& e)
{ }
catch(异常类型2& e)
{ }
(4)异常处理
根据捕获到的异常 进行相应的处理
能处理就可以进行处理 甚至能处理也可以进行继续抛出
不能处理就采用继续抛出 让上一层进行处理

 


***********************************************************

一. IO
1.1 C语言中的IO
fopen
fread
fwrite
fclose


1.2 C++中的IO

1.2.1 C++中的string
string
构造函数
string()
string(const char*)
string(const string&)

运算符重载
== != + += << >> []
成员函数
at length c_str()

1.2.2 C++和C语言IO的不同
C++中提供了一组类对C语言的IO函数进行了包装
标准的输入输出
istream ostream #include<iostream>
标准对象 cin cout
操作字符串的流
istringstream #include<sstream>
ostringstream
操作文件的流
ifstream ofstream fstream #include<fstream>

二.标准的输入输出对象
cin
cout :有缓冲,可以直接重定向
cerr :没缓冲,不可以直接重定向
clog :没缓冲,不可以直接重定向


三.C++中的非格式化IO
get() 得到一个字符
int get();
istream& get(char & ch); istream 变成 0

put 输出一个字符
ostream& put(char ch)

/* 读取一行数据 默认以"\n"结束 最多读取num-1个字符 */
istream& getline( char* buffer, streamsize num );
/* 读取一行数据 以delim字符结束 最多读取num-1个字符 */
istream& getline( char* buffer, streamsize num, char delim );

当流对象出错之后 就拒绝IO
纠正流(复位) clear
清理缓冲区用 ignore(num,'\n') 最多清理num个字符,直到'\n'

 

四.字符串的IO类
string abc;
格式化拼接 C语言中 sprintf
C++中可以使用字符串IO类完成。
istringstream 数据来源于字符串
ostringstream 把数据写入字符串

拼接字符串
string name="hello"
int age=20;
double salary=8805;

 

五.文件的IO类
ifstream :文件读取流
ofstream :文件输出流
fstream: 文件读写流
ostream& write(const char* buffer,streamsize num);
istream& read(char* buffer,streamsize num);
把一个对象的数据按照结构体为单位写入文件
然后把这些数据从文件中读取出来


六.文件的随即读写

seekg :调整读指针
seekg(大小,参考点)
参考点:ios::beg ios::end ios::cur

seekp :调整写指针
seekp(大小,参考点)
参考点:ios::beg ios::end ios::cur

tellg() 获取读指针的位置
tellp() 获取写指针的位置


七.格式化读取的控制


八.使用C++的文件输入和输出流读取一个文件 然后把读取到的内容的每个字符和一个0-255之间的字符 进行异或操作。把这些异或的内容写入一个文件中,这个过程相当于加密.然后运行程序传入加密文件名和解密文件名 密钥 这个相当于解密。

 

posted on 2015-12-05 13:58  LyndonYoung  阅读(192)  评论(0编辑  收藏  举报