C++期末备考笔记

建议使用notepad++文本编辑器打开,效果更佳


=================================================================================================

序言:了解标准C++
1,using 关键字的使用
2,C++中引入了四种强制类型转换运算符:
static_cast:标准转换及其逆转换
const_cast:转换const或volatile
reinterpret_cast:非标准强制转换
dynamic_cast:进行类对象之间的转换
3,从字符串处理看C++变迁
#include
strcpy();streln();stract();strcmp();strstr();
#include
new delete关键字用法


======================================================================================================
第九章:类的深入剖析
1,从结构到类
强类型语言,变量必须指明类型;
基本数据类型往往不够用;
比如:时间
C语言的解决办法:定义结构体
struct{
int hour;
int minute;
int second;
};
这样就定义了一种新的类型
声明一个时间变量
struct Time time;
time.hour,time.minute;
结构的成员变量;
结构指针:
struct Time *pt;
pt->hour=11;
C++中声明变量可以不用struct关键字
为保证程序的兼容性,推荐使用typedef声明结构变量
typedef struct Time{
·······
}Time;
Time time1,time2;
无法满足计算,或者输出表达,以及逻辑之间的关系

2,将数据和操作封装成为整体
类:比结构更加抽象的数据类型,除了包涵数据,
还可以包涵操作,并可进行封装!
从基本数据类型到类:
基本数据类型并不能方便的解决所有问题
复合数据类型是由基本数据类型组合出来的
抽象数据类型进而进化成为“类”
进而引出了新的编程思想:面向对象的程序设计


3,C++中类的定义:
class 类名
{
public:
//公有数据成员与成员函数
private:
私有数据成员与成员函数
}
【例】#ifndef TIME_H
#define TIME_H
class Time
{
public:
Time();
Time(int hour,int minute,int second);
int setTime(int,int,int);
int getTime();
private:
int hour;
int minute;
int second;
};
#endif;


特点:
类是一种智能的数据类型,知道自己的数据成员,成员函数,能对自己的数据和工作进行必要的保护:访问权限


接口与实现的分离:类的定义文件与实现文件的分离
Time.h Time.cpp;
编译时生成目标代码:.obj/.o
好处:容易修改,保持最小权限原则



类的成员函数:(注意包涵头文件)
.cpp实现文件中的成员函数实现
返回类型 类名::函数名(参数列表)
{
函数体;
}
也可以直接在.h文件中实现:
这样实现的函数为内联函数(inline),访问效率高,
功能简单,不易发生变化的可以放在头文件中实现



4,使用类的对象:
必须声明类的对象或使用对象的指针,引用
Time t1;
//声明t1对象,并分配对象的空间
//调用构造函数初始化(与简单变量不同)
Time &t2=t1;
//声明time类的一个引用,并将其指向t1对象
Time *t3=&t1;
//声明time类的一个指针,并将其指向t1对象
访问类成员:
->  .
t1.setTime(13,12,4);
t2.setTime(``);
t3->setTime();

get/set函数,工具函数




5,构造函数和析构函数:
对象的初始化(能否在类定义时为数据成员设定初值)
构造函数没有返回类型
构造函数可以重载(一个类可以有多个构造函数,只要其参数列表不同)
没有定义构造函数的类系统会自动调用缺省构造函数;
初始化时如何保证数据的合法性;
拷贝构造函数T::T(T&)
Time(Time&)
Time::Time(Time &t)
{
hour=t.hour;
minute=t.minute;
second=t.second;
}
【例】Time t1(24,0,0);
Time t2;
Time t2(t1);//拷贝构造
Time t3=t1;//拷贝构造

析构函数:~Time();
作用:释放对象在构造中分配的资源
每个类只能有一个析构函数,而且不能定义任何参数和返回类型
不能直接调用,由系统调用:
规则:创建对象是调用构造函数;
对象生命周期结束时,系统自动调用析构函数

【例】Time t1;调用
Time *t2;没有调用(并没有实际构造对象)
Time t3=&t1;没有构造新对象
t2=new Time(19.9.9);为一个对象指针分配空间,调用构造函数
delete t2;删除对象指针,释放对象空间,调用析构函数
}
程序结束,对象生命周期结束,自动调用t1对象的析构函数,t3只是一个引用,并没有分配空间,不调用析构函数。


封装性:


上机作业一:
Time.h文件
#ifndef DATE_H
#define DATE_H
#include
using namespace std;
class Date{
public:
Date();
int get
int nextDay()
void print()
Date(Date&);
~Date();

private:
int year;
int month;
int day;

};
#endif;

Time.cpp文件
#include "Time.h"

Time::Time()
{
}
int Time::


//
main.cpp文件

#include
using namespace std;
int main()
{

}


======================================================================================================
第十章:类的深入剖析(II)


1,常量:
const:常量说明符
用于冻结一个变量。使其在程序中不能被修改。
使用const声明变量时必须对变量进行初始化
修饰一个简单变量
修饰函数的输入参数
修饰函数的返回值
修饰类的成员函数
【例】const int *p1=&b;指向int常量的指针
int const*p2=&b;指向int常量的指针
int *cons p3=&b;指向int变量的常量指针
int *p1;
const int a=10;
p1=&a;//编译错误
p1=const_cast(&a);//B
*p1=5;
cout<<"a="< return 0;
}
const修饰输入参数,不修饰输出参数

const修饰类的成员函数(不会修改数据成员的成员函数)
不慎修改数据成员或者调用非const成员函数,将出现编译错误
【例】int getMark() const;
使用const对象:
Time wakeup(6,40,0);
const Time noon(12,0,0);
wakeup.setHour(7);
noon.setHour(13);//?不可以
noon.print();//?可以
常量在何时指定初值:
只能在定义的时候初始化:const int i=10;
类中的常量数据成员只能在构造函数中初始化,但又不能在构造函数中初始化,需要采用成员初始化器的方式进行初始化
Time::Time(int c,int i):noon(i),count(c){}


const修饰成员函数常见错误:
1,修改数据的定义为const函数
2,调用非const函数
3,const对象调用非const成员函数
4,构造和析构函数声明为const
5,不为祁提供成员初始化器
mutable类成员:
代替const_cast,

组成:对象作为类的成员
把其他类的对象作为其数据成员是一种重要的软件复用技术
类成员的初始化:
类似于const常量初始化,需要在构造函数的成员初始化器中进行初始化
【例】Employee(char *n,int y,int m,int d):birthDate(y,m,d){}
使用Employee对象:~~~
class Employee{
public:
……
private:
char name[25];
const Date birthDate;
const Date hireDate;
};
**类对象和数据成员对象的构造顺序:
基本原则:先别人,后自己
类对象和数据成员对象的析构顺序:同一作用域内,先构造的后析构,后构造的先析构
================================================================
友元函数和友元类:
希望本类以外的对象或函数能够访问类中的私有成员
友元:本类外的对象(友元类)或函数(友元函数)提供了访问途径
(friend):一个类的友元可以访问这个类的私有成员
!!!友元使得数据的封装性受到影响,可维护性变差,慎重使用


友元函数:不属于任何类,是某个类的友元的一般函数
友元成员:是某个类的成员函数,当前类的友元:
friend 返回类型 类名::函数名(参数列表)
友元类:friend class 类名

====================
友元关系的一些性质:
是给予不是索取
不对称,不传递
友元函数不是类的成员函数;

====================
this指针和动态内存分配
c++为每一给类提供一个this指针
指向当前对象
通过this指针访问当前对象的成员
说明:
在非静态成员函数中使用this指针
友元函数不是成员函数没有this指针
注意友元成员函数中this指针所指向的对象
this指针的用法:
this->x;
(*this).x;


串联函数的调用:Time类同时修改hour,minute
使用this指针实现串联函数的调用:
返回当前对象的引用,不是指
==================================================
Time &Time::setTime( int h, int m, int s ) {
   setHour( h );   setMinute( m );    setSecond( s ); 
   return *this; 

Time &Time::setHour( int h ) {
   hour = ( h >= 0 && h < 24 ) ? h : 0;
   return *this; 

Time &Time::setMinute( int m ){
   minute = ( m >= 0 && m < 60 ) ? m : 0; 
   return *this; 

====================================================
动态内存分配:new delete关键字的使用
new语法格式:
格式1:指针标识符 = new  类型标识符;
格式2:指针标识符 = new  类型标识符(初始化值);
格式3:指针标识符 = new  类型标识符[数组维数];
delete语法格式:
格式1:delete 指针标识符;
格式2:delete[]指针标识符


组合指针成员:编写字符串类
!!!!涉及到动态内存分配问题必须写拷贝构造函数
========================================================
静态类成员:
static关键字用法:
普通类成员需要通过类对象去访问,实际中属于当前对象
static类成员:属于类的而不是某个对象,所有对象共享
静态数据成员
静态成员函数
所有对象共有的一个数据成员,其值可以被任何一个对象所改变
必须在使用前初始化const static可以再类定义声明中初始化
其他static必须在类的定义体外初始化:
数据类型 类名::静态数据成员=初值;//静态数据成员名(初值);
 为什么不在定义中初始化!!!!
静态成员函数:(不与任何对象联系,不存在this指针)//思考
不能声明为const成员函数
在静态成员函数中只能访问静态数据成员或全局变量,如果要访问非静态数据成员,利用参数传递进行(以限定哪个对象的数据)
静态类成员的访问:
使用静态数据成员 
//cpp文件中初始化静态数据成员 int A::x(0);   //或者:int A::x=0


======================================================================================================


第十一章:运算符重载


1,运算符基础:
分类:单目,双目。三目
运算符重载:将运算符看成是预定义关于简单类型的运算符函数,重载就是对这些函数进行的关于类的对象的运算的重载
关键字:“operator运算符名”参数为运算符所需的操作数
【例】operator+(a,b);
. :: ?: sizeof 不能被重载
运算符重载注意事项:
需要显示地重载某个运算符
不要改变运算符的意义


2,用类成员或全局函数作为运算符函数
作为复数类的成员函数
    作为一个普通的全局函数,此时由于需要操作复数类的私有数据成员(可以通过get函数访问,但是会降低访问效率),
因此经常把该全局函数设置为复数类的友元函数
friend Complex operator+(Complex&, Complex&);
作为全局函数的重载:(用友元)
用作类成员重载运算符函数:对于二元运算符其最左边的操作数必须是该类的对象
Complex opeartor+(Complex&);


重载流运算符:
friend ostream& operator<<(ostream&, const Complex&);
operator++(c);//前置运算符不变
operator++(c, int);
对于左值运算符,重载时必须返回引用,以便能够连续运算和接受赋值


拷贝构造函数:在参数传递(值传递)、函数返回值(值返回)、对象初始化等需要自动生成新对象时,编译器利用拷贝构造函数完成对象拷贝,从而避免自动内存拷贝带来的问题






======================================================================================================
第十二章:继承

1,继承:基类和派生类
C++是一种强类型语言,每个数据类型之间都是相互独立的,
而现实应用中很多类型之间存在紧密的联系


类型之间存在Is-a的关系、父子关系
A is a kind of B
A继承B
利用继承实现代码复用
**C++面向对象三大特性:多态,继承,封装


基类是对若干派生类的抽象!!!
派生类是对基类的具体化(通过增加数据成员或成员函数将基类变为某种更有用的类型

class 派生类名:继承类型 基类名
{
·······
}


2,protected成员:
基类的成员有两种可见性:
private:只能被基类成员和该类友元访问
派生类的成员函数不能访问基类的私有成员
于是:
基类的protected成员只能被基类的成员函数和友元以及派生类的成员函数和友元访问
破坏了封装性

3,使用继承建立系统层次:
【例】雇员工资支付系统
派生类继承基类所有成员
派生类可以重新定义基类的成员函数
派生类可以添加自己的新成员
派生类如何初始化基类成员:通过成员初始化器:调用基类的构造函数进行初始化
派生类不能访问基类的私有成员
派生类通过访问函数访问基类私有成员

4,派生类中直接使用基类同名函数:重新定义,重载
派生类中引用该成员函数,会自动选择派生类版本
作用域::科用来从派生类中访问基类该函数版本
派生类成员函数部分功能已由基类是吸纳:
在派生类中直接调用:基类名称::函数名


5,派生类中的构造函数和析构函数!!!!
1,派生类的构造函数的调用次序:
先基类成员,再基类,再派生类成员,再派生类
派生类不继承基类的构造函数和赋值运算符
派生类的构造函数和赋值运算符能调用基类的构造函数和赋值运算符(可隐式调用也可显示调用)
派生类的构造函数总是先调用其基类构造函数来初始化派生类中的基类成员
如果省略派生类的构造函数,那么就由派生类的默认构造函数调用基类的默认构造函数
2,派生类的析构函数调用次序(调用原则):
在同一作用域内,后创建的先析构,先创建的后析构(派生类的析构函数在基类的析构函数之前调用)
析构时总是调用自己类的析构函数
6,类对象的指针
1,一般对象的指针:
各类指针相互独立,不能混用
2,基类指针和派生类指针
派生类指针与基类指针相互独立又存在继承与被继承的关系

派生类的指针与基类指针相互之间的关系:
1,派生类指针不可以指向基类对象
2,基类指针可以指向派生类对象,但不可以通过该指针访问不属于基类的数据成员
3,!!!!!
通过指针对成员函数的调用,仅与指针本身的类型有关,与指针指向的当前对象无关;可通过强制类型转化来建立于当前对象的关系
4,派生类对象和基类对象不能互相赋值
5,引用的访问规则与指针相同
7,派生类中基类的初始化问题:
构造派生类时会自动构造基类,基类如何构造
1,利用成员初始化器调用基类的构造函数
2,指缺省构造函数

复合与继承的区别:复合(整体拥有部分)
8,三种继承类型:
访问权限的问题!!


9,基类中的静态成员:
基类中的静态成员不受继承类型影响,在整个类层次中均可以访问
派生类中访问基类静态成员必须显示说明:
类名::成员

10,多重继承:
由多个基类派生而成新的类:C++支持
由此产生很多问题:
二义性:解决办法:加类名::成员名
虚拟继承
多重继承构造函数的调用:
 先基类,后成员,再自己
同一层多个基类,先虚基类后非虚基类

======================================================================================================


第十三章:多态
1,通过RTTI使用派生类成员
由学生选课系统产生实际应用问题
基类指针为访问派生类对象需要进行强制类型转换
而课程信息是在运行过程中动态添加的,如何知道它的类型呢
RTTI(运行时类型信息)#include
作用:1,获得类型信息
2,将基类指针(引用)转换成派生类指针(引用)
dymanic_cast
     dynamic_cast(s[i]).setGrade(grade));
dynamic_cast<目标类型>(变量名)
2,为了进一步满足这种需求:
虚函数和多态
1,多态是同意函数接口可以有不同的实现:
通过基类提供的接口就可以实现调用派生类不同的实现
C++中通过虚函数来实现多态性
通过虚函数调用机制,自动进行“匹配”
2,虚函数:是一种动态的函数重载的方式,它允许函数调用与函数体之间的联系是在运行时才建立的;这样可以根据运行时所指向的
对象来调用不同的函体
3,C++中虚函数的定义:
virtual 返回类型 成员函数名(参数列表);

关于虚函数:
必须是成员函数
继承层次中都是虚函数
最好每一层显示的声明为虚函数
静态函数不能定义为虚函数
!!!!!
只有虚函数才支持多态调用,普通成员函数的调用规则只与指针类型有关
3,纯虚函数与抽象类:
1,虚函数的作用:
……virtual int getScore() const; ……
但该函数在基类中却无法实现?
所有的实现逻辑都在派生类中,写该函数目的不是为了复用代码,而是为了可以通过基类指针调用getScore()函数(即支持多态调用)
2,通过基类指针指向派生类对象来实现多态的目标:
同一指针/引用指向不同对象时具有不同的行为
3,但该指针不能访问派生类成员
导致虚函数提供接口
该函数可以部分实现也可以完全没有实现(纯虚函数)
提供访问接口(Interface)
纯虚函数:virtual 函数返回类型 函数名(参数列表)=0;
作用:为基类提供派生类访问接口,达到多态的传递特性
4,由此产生抽象类:
如果某个基类中存在纯虚函数,此时不能通过该基类创建一个基类对象
这种基类就是抽象基类,不会生成任何对象,只是为派生类提供访问接口和部分公有代码的实现
【实例】应用多态开发的工资发放系统/图形库系统
~~~~~~~
5,虚析构函数:!!!
构造函数构造对象的类型是确定的,不需要也无法根据类型表现出多态性,故不能定义为虚函数
析构函数可通过父类指针(或引用) delete调用,父类指针指向的对象类型可能是不确定的,
因此析构函数应该定义为虚函数
特点:
如果基类析构函数虚则派生类虚
虚析构函数的目的在于在使用delete运算符删除一个对象时,能够保证所执行的析构函数就是该对象的析构函数
如果采用动态内存分配的形式创建基类或派生类,则一定要将基类和派生类的析构函数定义为虚析构函数,
否则便可能造成内存泄漏,导致系统出现内存保护错误
6,多态的底层实现机制:
类是一种抽象数据类型,只有在生成类的对象后才会为其对象分配内存空间
非静态数据成员;成员函数(独立代码空间)静态成员(独立数据空间)
对象大小不可能为0
对象的大小!!
C++中动态绑定实现机制:virtual:放置秘密指针
======================================================================================================
第十四章:模板


1,从宏到模板
1,预处理指令
#define 与const
区别在于define定义的是替换文本,在编译前进行替换
const定义的是一个变量符号,运行时直接引用
const常量具有数据类型
宏:#define 替换文本
模板:完全基于函数调用机制,与普通函数效果相同
2,函数模板
:C++提供的一种强大的软件复用机制
基于泛型编程思想
模板的定义:
template  < 模板参数表>   函数/类声明
对于功能完全相同、仅仅参数类型不同的重载函数,
可以写一个函数模板,然后请编译器“代劳”
函数模板是一个抽象定义的模板,在实际调用时实例化为相应的模板函数
可以重载函数模板
3,类模板:
~~~~~~~
4,非类型参数
~~~~~~~~
5,模板与友元,继承,和静态成员
~~~~~~~~
6,标准模板库:
三大关键组件:容器,算法,迭代器
STL:Standard Template Library

======================================================================================================
第十五章:流
1,文件和流:
数据存储在变量中,临时的,需要长期存储,存储在外部设备中
操作系统提供的对数据存储和组织的方式
将相关的数据按照一定的格式存储在一起,并通过文件名进行访问(读和写)
同时为了区分不同格式的文件,操作系统引入了扩展名来表达不同的文件类型
file1.txt、file2.doc、file3.jpg、file4.exe
计算机处理的数据最终都会被简化成为0和1的序列
1,访问文件的基本思路
把文件看成是字节流
从该字节流中读取若干个字节
按照文件格式,解释所读取的字节流,翻译成所需要的内容
2,C++文件操作核心技术:
如何把文件与某一个流关联起来
从该流中获取指定的字节序列
2,C++中流技术的实现
1,关于字符编码
2,C++中流库处理
iostream istram ostream
fstream strstream;
3,采用流技术操作顺序文件
fstream ifstream ofstream
文件操作基本步骤:
打开,读写,关闭
1,打开文件:建立流对象,与外部文件关联并指定打开方式
打开方式:(open函数,构造函数)
ifstream infile;
infile.open("hah.cpp";ios::in);
ifstream infile("haha.cpp",ios::in|ios::out);
打开文件后要判断读是否成功
is_open();
2,关闭文件:
对象名.close();
3,关于文件的分类:
文本文件和二进制文件(ios::binary)
4,创建并写入顺序文件
写入文件是对文件的输出操作:文件输出流:ofstream (ios::out)
5,读取顺序文件是从文件中的输入操作 :ifstream(ios::in)
按照写入时的格式读取文件,并存入到相应的变量中
6,更新顺序文件
4,随机存取文件:
顺序文件的缺点:
引入随机存取文件:
每条记录大小相同
不考虑各字段的数据类型,直接以二进制格式存储
5,标准输入输出流:
预定义标准流对象:cin,cout,cerr,clog
6,流错误处理:
~~~~~~~~


======================================================================================================
第十六章:异常处理
1,从错误处理到异常:
多数情况下程序员可以预知的,因此可以提前对这些情况进行处理,这就是异常处理
2,异常处理:
对所有能预料运行错误进行处理的机制
相对于传统处理方法
提高程序的可维护性,程序结构清晰
3,C++中的异常处理机制:
C++异常处理关键字:throw catch try
异常处理的一般过程:
定义异常类:用于记录异常信息
抛出异常throw
捕捉异常try catch
1,异常类:
属性用于基类异常发生时产生的信息:const char *message;
方法用于访问。操作这些异常信息:const char *what(){return message};
2,抛出异常
if(a==0)
throw DivideByZeroException();
利用throw语句抛出异常对象
外部的应用程序使用这个异常对象来进行异常处理
try{
cout<<"结果:"< }catch(DivideByZeroException ex)
{
cout<<"出现异常"< }
3,捕获异常:
利用try catch在可能产生异常的程序段中捕获异常
1,利用try{}定义需要捕获异常的程序段
2,利用catch{}捕获各种可能的异常,并进行后续的处理
4,异常处理过程解析:
throw:用于引发异常,传播异常
try:
catch:
catch(....)表示捕获所有异常//放在其他catch前,则其他的无法执行
异常匹配
5,异常处理中的相关问题:
异常指定
1,异常处理与构造函数:
6,标准库中的异常处理:
头文件
头文件
exception() throw();

======================================================================================================
第十七章:GUI编程基础
1,基于资源的程序设计
1,实现与用户交互的界面
2,完成所需业务功能的代码
2,两类GUI
基于窗体From
基于Web
3,事件 
消息:
事件发生后操作系统产生相应消息一通知应用程序
#define WM_COMMAND 0x011即消息可以用一个整数表示
输入消息
控制消息
用户消息
系统消息
4,窗体风格的GUI程序设计
C++ 图形开发平台
注册窗体类
创建窗体
显示和更新窗体
创建消息循环
终止应用程序
MFC编程体现面向对象的特点
5,Web程序设计:

======================================================================================================
复习题:
ppt10,ppt13,ppt21,ppt22, C++期末备考笔记_第1张图片

你可能感兴趣的:(C/C++)