




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
面向对象程序设计
第一章面向对象的基本概念软件的外部质量正确性健壮性可扩充性可复用性第一章面向对象的基本概念2.模块化模块化标准模块的可分解性(图1.1)模块的可结合性(图1.3)模块的可理解性(图1.4)模块的连续性模块保护模块化原则语言模块单元信息隐藏原则第一章面向对象的基本概念软件复用代码复用设计过程复用分析方案复用第一章面向对象的基本概念为什么要面向对象程序中各种成分的特点:接口:极为易变功能:很易变过程执行顺序:很易变数据:极为易变对象:最为稳定面向功能的方法的缺陷:可扩充性、可维护性、复用性的问题。第一章面向对象的基本概念5.面向对象的基本概念面向对象的含义面向对象开发的含义面向对象的主题面向对象的含义面向对象是把软件系统看成是一系列对象的集合对象包括数据结构,也包括行为面向对象的四个特性标识唯一性分类性多态性继承性标识唯一性每一个对象都有一个唯一的标识通过标识找到对象对象的查找方法统一且独立于对象的内容分类性具有相同数据结构和行为的对象构成一个类。类是一种抽象:它反映了与应用有关的重要性质,而忽略了一些无关的内容。多态性同一个操作可以是不同的类的行为继承性类之间形成一种层次性的结构。父类的性质可以被子类继承。减少了程序设计的重复性。代码复用快速原型技术面向对象开发的含义建摸开发过程中真正有意义的成效来自于对象的概念,而不是实现。方法学分析系统设计对象设计实现面向对象开发的含义(续)三种模型对象模型动态模型功能模型对象模型对象模型即描述对象的结构对象的唯一标识与其它对象的关系对象的属性对象的操作动态模型动态模型描述与时间和操作次序有关的系统属性:触发事件事件序列事件状态事件与状态的组织动态模型关心的是控制。动态模型用状态图来表示。功能模型功能模型描述与值的变化有关的系统属性:功能、映射、约束、依赖条件等功能模型用数据流图表示。模型之间的关系对象模型描述了动态模型和功能模型中的数据结构;对象模型中的操作对应于动态模型中的事件和功能模型中的功能。动态模型描述了对象模型中对象唤醒、和动态模型中行为的唤醒的功能。功能模型说明说明对象模型中操作的含义和动态模型中的行为的意义,以及对象模型中约束的意义。面向对象的主题抽象封装归并数据与行为共享抽象强调实体的本质、忽略无关紧要的属性决定对象时:研究对象的意义和行为继承性强化了抽象的机制:避免过早地考虑细节问题封装对象的内部实现细节对象独立的外部性质分离实现细节与接口合并数据与行为归并数据与行为类层次过程层次数据层次共享在同一个应用项目中共享:继承在不同的项目中共享:类库#include<iostream.h>voidmain(){ intj=3; cin>>j; cout<<“j=“<<j<<endl;}2.关于注释/*comments*/编译程序略去注释对之间的内容//comments编译程序略去注释符后面的内容3.预处理#include#include<….h>在系统指定的目录中寻找头文件#include“…h”在系统当前目录中寻找头文件3.预处理#define#include<iostream.h>#defineHELLO"Hello,world!"voidmain(){ cout<<HELLO<<endl;}3.条件预处理#if,…#include<iostream.h>#defineDEBUG0voidmain(){ intj; j=5;#ifDEBUG cout<<"j="<<j<<endl;#endif}3.条件预处理#ifdef,…//2_5_4.cpp#include<iostream.h>#include"2_5_4.h"#include"2_5_4_1.h"voidmain(){ cout<<"x="<<x<<endl;}//2_5_4.h#defineXDEFintx=2;//2_5_4_1.h#ifndefXDEFintx=2;#endif4.数据类型的初步知识基本数据类型char,int,float,double,void修饰符signedunsignedlongshort4.数据类型的初步知识#include<iostream.h>voidmain(){ cout<<sizeof(char)<<endl; cout<<sizeof(int)<<endl; cout<<sizeof(float)<<endl; cout<<sizeof(double)<<endl; cout<<sizeof(longdouble)<<endl;}输出结果:144884.数据类型的初步知识复合数据类型结构联合位域枚举类5.常量整型常量浮点常量字符常量字符串常量6.变量变量的意义变量名匈牙利命名法:小写字母开始表示变量类型其余的名字表示变量的功能。例如;nCharacterCounter
整型变量、保存字符数。保留字不能作变量名变量的定义7.指针类型定义:类型*指针类型变量初始化同类型变量的左值:*p=&x;同类型指针变量:p=q;动态分配的地址:int*p=new(int);int*p=malloc(sizeof(int));7.指针类型指针运算#include<iostream.h>voidmain(){ inti=1,j=2,k=3; int*p=&j; p=p+1; *p=*p+2;
cout<<i<<endl; cout<<j<<endl; cout<<k<<endl;}输出结果:323#include<iostream.h>voidmain(){ char*st="Theexpenseofspirit"; intlen=0; char*p=st; while(*p++)len++; cout<<len<<":"<<st<<endl;}#include<iostream.h>voidmain(){ char*st="Theexpenseofspirit"; intlen=0; while(*st++)len++; cout<<len<<":"<<st<<endl;}8.引用类型定义intval=10;int&refVal=val;refVal+=2;//nowval=128.引用类型引用必须初始化不能再作其它变量的引用引用可以直接由一个右值去初始化,这时一个内部的临时变量用于取得这个右值,然后引用使用这个临时变量来进行初始化用不同类型的对象初始化时,同样会由系统生成一个临时变量。9.常量类型const必须被初始化定义后就不能被改变常量的地址不能被赋给一个指针constinta=3;int*p=&a;9.常量类型常量的指针:指针指向一个常数常量指针能再指向其它地址constint*p;intj,k;p=&j;p=&k;常量指针所指的对象不能通过这个常量指针来改变值constint*p;intj;p=&j;*p=*p+1;9.常量类型指针常量:指针是一个常量,但所指的变量未必是常量定义interrNum;int*constcurErr=&errNumb;可以改变指针常量所指的对象*curErr=1;*curErr=2;不可以改变指针常量curErr=&x;curErr=y;//Error例:程序2_11_1.10.枚举类型枚举类型是整型符号常量的集合。枚举类型对象中的元素没有内存地址。在默认的情况下第一个元素的值为0。每一个元素都可以被明确赋值。一个元素若没有被明确赋值,则它的值是前一个元素的值加1。举例11.数组类型一维数组:类型变量[数组大小];二维数组:类型变量[数组大小][数组大小];数组类型与指针的关系:&buf[0]与buf具有相同的意义。数组名不能运算:++buf是错误的。12.自定义类型名定义:typedef类型自定义类型;作用改善声明过程:举例2_15.cpp移植的方便typedefintADDRADDRa;ADDRb;typedeflongADDRADDRa;ADDRb;3.10类型转换类型转换:不改变二进制的结构,但用不同的方式解释这些数据。3.10.1隐式类型转换在算术表达式中,具有较大空间的数据类型成为最终结果转换成的数据类型。例如:intval=3.14159;//转换成3val+3.14159;//val先转换成3.0,结果6.14159例intI=10;I*=2.3;cout<<I;运行结果:233.10.2显式类型转换在{intk;k=k+3.14159;}中将k转化成double;计算表达式值将表达式的类型转化成int在{intk;k=k+(int)3.14159;}中只有一次类型转换void*的指针可以指向任何数据,但不能直接引用void*的指针不能直接赋值给其它类型的指针void*用于对象类型未知或随状态而改变的情况3.10.2显式类型转换#include<iostream.h>voidmain(){ inti=10; //int*ip; void*vp; doubled=3.14159; //ip=&d;//cannotconvertfrom'double*'to'int*' vp=&d; cout<<*(double*)vp<<endl;}3.10.2显式类型转换{ void*vp; double*dp; doubled=3.14159; vp=&d; //dp=vp;//error:cannotconvertfrom'void*'to'double*' dp=(double*)vp;}3.11语句用分号结束一条语句最简单的语句是“空语句”:;复合语句用花括号括起来的一系列语句组成复合语句作未一个单一的单元出现在单一语句出现的任何地方复合语句不需要以分号终结3.12if语句语法结构:if(表达式)语句表达式必须放在括号中。表达式为非0时,表示真,并执行语句容易出现的错误1:经常忘了复合语句的花括号3.12if语句#include<iostream.h>voidmain(){ inti=0; if(i) cout<<"first"<<endl; cout<<"second"<<endl;}输出结果:second3.12if语句#include<iostream.h>voidmain(){ inti=0; if(i){ cout<<"first"<<endl; cout<<"second"<<endl; }}这个程序没有输出3.12if语句if-else语句:if(表达式) 语句1else
语句2语句1若不是复合语句则必须有分号
3.12if语句嵌套的if语句中else匹配的时离它最近的if语句:if(exp1) if(exp2) s1; else s2;
#include<iostream.h>voidmain(){ intk=0,n=1; if(k) if(n) cout<<"first"<<endl; else cout<<"second"<<endl;}//3_12_2.cpp没有输出#include<iostream.h>voidmain(){ intk=0,n=1; if(k){
if(n) cout<<"first"<<endl;}
else cout<<"second"<<endl;}输出:second#include<iostream.h>#definesize5voidmain(){ intia[size]={3,1,2,9,1}; intminVal=ia[0]; intoccurs=1; for(inti=1;i<size;i++){ if(minVal==ia[i]) ++occurs; else
if(minVal>ia[i]){ minVal=ia[i]; occurs=1; } } cout<<"minVal="<<minVal<<endl; cout<<"occurs="<<occurs<<endl;}3.13switch语句格式:Switch(表达式){
caseexp1:语句1;break; …………….. caseexpn:语句n;break;}exp1,…expn都是常量表达式如果语句1,…,语句n后没有break,则继续执行下一行语句。3.13switch语句Default语句Switch(表达式){
caseexp1:语句1;break; …………….. caseexpn:语句n;break; default:语句n+1;}3.14循环语句3.14.1while语句格式及意义while(表达式)语句只要表达式真,就执行循环体语句。例3_14.cpp3.14.2
for语句格式for(init_statement;expr1;expr2)语句语义执行init_statement;计算expr1;如果expr1非0,则执行语句;否则结束for语句。执行expr2;转23.14.2
for语句for(;;)无限循环#include<iostream.h>voidmain(){ inti=0; for(;;){ if(i>5)break; cout<<i<<endl; i++; }}3.14.3
do语句格式do
语句while(expr);#include<iostream.h>voidmain(){ inti=0; do cout<<i++<<endl; while(i<5);}4.1成员变量和成员函数4.1类的定义定义类:classStack{ …};定义类并说明对象classStack{ …}obj1,obj2;4.1.2成员变量1.与声明变量的方式相同声明中不允许进行初始化赋值classStack{ int*lst; intmax_size; intnb_elements;};classStack{ int*lst; //error intmax_size=0; intnb_elements;};4.1.2成员变量3.成员变量可以使任何类型classStack{ int*lst; intmax_size; intnb_elements; Stack*s;};classStackofStack{ inttopStack; Stackstackstorage[5];};4.1.2成员变量4.提前声明:一个类提前声明之后,这个类的对象指针、引用可以作为另一个类的成员变量。
classStack;classStackofStack{ inttopStack; Stack*stackstorage;};
但这个类的对象不能作另一个类的成员变量。4.1.3成员函数在定义体外定义4_1_2.cppclassStack{ intempty(); voidpop(); inttop(); voidpush(int);};intStack::empty(){return(nb_elements==0);}4.1.3成员函数在定义体内定义4_1_2.cppclassStack{ intempty(){return(nb_elements==0);} voidpop(); inttop(); voidpush(int);};4.1.4信息隐藏原则:将类的功能描述部分作为共有部分接口提供给用户;将数据的具体表示、具体实现作为私有部分隐藏起来。成员函数友元派生类其它privateYNNprotectedYYNpublicYYY4.1.4信息隐藏例共有部分-私有部分intempty();voidpop();inttop();voidpush(int);int*lst;intmax_size;intnb_elements;4.1.5对象与类类对象对象的说明类对象1,对象2,对象n;4_1_2.cpp4.1.6const成员函数声明为const的对象是不能被赋值的声明为const的对象不能随便调用任意的成员函数声明为const的对象只能调用声明为const的成员函数const的成员函数不能改变成员变量4.2构造函数与析构函数构造函数4.2构造函数和析构函数4.2.1对象的初始化构造函数用来在声明对象时,初始化成员变量。4_2_1.cpp如果定义了构造函数,则在声明对象时所带参数类型必须与某一个构造函数的的参数类型一致。4_2_1.cpp如果没有定义构造函数,则在声明对象时不带参数。4_2_0.cpp4.2.2构造函数的定义构造函数不允许指明返回类型,也不允许返回一个值。构造函数的名字必须与类的名字一样。构造函数可以重载:有多种定义,每一种定义的参数表不一样。声明对象时参数类型必须与一个构造函数的参数类型一致。构造函数一般说明为public。例4_2_2.cpp构造的调用:明确调用方式Strings1=String(“rose”);Strings2=String(3);Strings3=newString(“rose”);简化调用方式Strings3(“rose);Strings4=“rose”;例4_2_3.cpp用无参数构造函数初始化对象不定义任何构造函数定义无参数的构造函数例:4_2_4.cppStrings();不是声明无参数的对象,而是不带参数的返回类型String型对象的函数。4.2.3析构函数4.2.3.1对象的生存期对象的生存期4_2_3_1.cpp一个对象在退出作用域时,系统要回收其空间。在退出对象指针时,如果没有调用delete则不会释放指针所指的空间。4.2.3.2系统回收空间LenStrLenStrLenStr{deletestr;}{}LenStr系统回收垃圾空4.2.3.3析构函数格式:~类名();析构函数不带参数,没有返回值。例4_2_3_2.cpp4.2.3.4显式调用析构函数如果只想执行析构函数中的执行的操作,而不释放对象的空间,则可以显式调用析构函数。pb->String::~String();执行析构函数中的执行的操作。pb->~String();执行系统的析构函数,释放对象的空间。4.2.4类/对象数组定义constsize=16Stringtbl[size];String*tbl=newString[size];访问数组对象tbl[I].display();4.2.4类/对象数组初始化Strings[]={“rose”,“sbeef”};Stringt[]={String(),String(3);String(“rose”)};删除delete[2]s;delete[3]t;4.2.5对象成员构造函数的执行次序:对象成员的构造函数先初始化,然后才是包含它的类的构造函数。有多个对象成员时,按照在类的定义中声明的次序初始化。4_2_5_1.cpp对象成员的初始化参数由初始化表提供。初始化表只能出现在构造函数的定义体中,不能出现在构造函数的声明中。(MSVC++没有这个限制。)4.2.5对象成员const成员必须在成员初始化表中初始化。4_2_5_2.cpp。成员对象的初始化参数可以是同一类型的另一个对象。4_2_5_3.cpp。多层成员对象初始化的次序。4_2_5_3.cpp。4.2.6成员初始化通过另一个对象初始化编译器定义的拷贝函数X::X(const&X);String::String(const&String&s){ len=s.len; str=s.str;}//浅拷贝4_2_6.cpp4.2.7构造函数X::X(const&X)String::String(constString&s){ len=s.len; str=newchar[len+1]; strcpy(str,s.str);};//深拷贝4_2_7.cpp4.3静态成员变量和静态成员函数某个类的所有对象都共同访问同一个变量。全局变量的缺点静态成员变量类的所有对象都共享静态成员变量图4.7声明:static类型变量初始化:类型类名::变量=初始值;初始化时不加static初始化时不用加private、public、protected初始化时用域作用符::说明所属类。4.4内联函数使c++编译器在函数调用处以代码体内联来替换对函数的调用。4.5友元成员函数派生类其它privateYNNprotectedYYNpublicYYY4_5_1.cpp4.6对象和动态对象4.6.1this指针一个类所有的对象的成员变量除了静态变量外都有独立空间,但同一个类的所有对象成员共享同一组成员函数。一个对象调用自己的成员函数时,将this指针传递给这个成员函数,这个this指针指向这个对象。例:4_6_1_1.cpp4.6.1this指针成员函数翻译成非成员函数voidStack::empty(){ return(nb_elements==0);}voidempty__Stack(Stack*this){ return(this->nb_elements==0);}成员函数翻译成非成员函数voidStack::push(intelements){ if(nb_elements<max_size) lst[nb_elements++]=elements;}voidpush__Stack(Stack*this,intelements){ if(this->nb_elements<this->max_size) lst[this->nb_elements++]=elements;}连续操作,返回this指针4_6_1_2.cpp4.6.2动态对象用new代替malloc、alloc等用delete代替free变量指针=new类型;变量指针=new类型(初始值);变量指针=new类型[size];变量指针=new类型[size][size];delete变量指针;delete[size]变量指针;初始化与数组对象用new分配一个对象时,可以直接初始化。用new分配一个对象数组时,不可以直接初始化,并且对象必须有一个无参数构造函数。例:4_6_2_1.cpp例:4_6_2_2.cpp例:4_6_2_3.cpp5.1结构5.1.1结构的定义与结构变量的声明structexample{inta; floatb;}structexamplee1,e2;typedefstructexample{inta; floatb;}EXAMPLE;EXAMPLEe1,e2;5.1结构5.1.1结构的定义与结构变量的声明structexample{inta; floatb;}examplee1,e2;structexamplee3,e4;5.1.2结构作为类结构中也可以引入成员函数在缺省的情况下结构的成员是public例:5_2_1.cpp5.2.1联合作为类联合的成员变量共享内存同一个单元在缺省的情况下,联合成员是公有的联合可以包含成员函数联合不能继承其它的类联合不能有序函数静态变量不能是联合如果有构造、析构函数,则对象不能是联合的成员例:5_2_1_1.cpp5.2.2匿名联合匿名联合不含类型名变量不能被说明为这类联合联合的成员变量要共享同一个单元联合的变量直接引用例:5_2_2_1.cpp匿名联合不能有成员函数匿名联合不能有private,protected全局匿名联合必须是静态的。6.1函数函数的声明[inline][返回类型]函数名(形式参数表);形式参数表:[类型[变量名]{,类型[变量名]}]例:voidf(int);intgcd(int,int);inlineintmin(intj,intk);6.1.1递归一个函数如果直接或间接地调用自身称为递归函数。例6_1_1_1.cpp6.1.2内联函数内联函数与直接代码比较的优点可读性容易修改类型检查复用6.1.3强类型检查所有函数调用的参数表和返回值都要进行类型检查。如果一个实参类型与函数原型声明的形式参数不匹配,则首先使用隐式类型转换,若隐式类型转换无法进行,或参数个数不符,则给出编译错误。6.1.4返回值数组类型、函数类型不能作为返回类型。数组类型的指针、函数类型的指针可以作为返回类型。默认的返回类型是int。6.1.5函数参数表参数表语法结构intfork();intfork(void);等价。函数声明中可以只出现类型不出现参数名。有参数名可以增加可读性。函数定义中必须出现类型和出现参数名。参数个数不定的参数表例6_1_5_1.cpp有缺省值参数有缺省值参数必须放在最后6.1.6参数传递传值参数传递将实际参数的右值复制到形式参数的存储空间。不适合传递大量数据不适合返回计算结果指针参数传递引用参数例:6_1_6_1.CPP6.1.7引用参数参数传递方式类似与指针参数传递程序书写方式类似与传值参数传递6.1.8数组参数一下三种声明等价:voidf(int*);voidf(int[]);voidf(int[10]);编译器和函数都不检查数组参数的个数voidf(int*,intsize);voidf(int[],intsize);voidf(int[10],intsize);6.1.8数组参数多维数组参数
intf(intmatrix[][10],introwSize);intf(int(*matrix)[10],introwSize);6.1.9作用域文件域局部域、局部块域类域域操作符:::使程序可以处理被隐藏的外部变量外部变量静态外部变量6.1.10局部域将局部变量的地址传出是一个严重的错误:intf(inta,intb){ return&a;}静态局部变量寄存器型局部变量作业建立一个保存整数的环形队列存放数据读取数据。。。。。6.1.6参数传递传值参数传递将实际参数的右值复制到形式参数的存储空间。不适合传递大量数据不适合返回计算结果指针参数传递引用参数例:6_1_6_1.CPP6.1.7引用参数参数传递方式类似与指针参数传递程序书写方式类似与传值参数传递6.1.8数组参数一下三种声明等价:voidf(int*);voidf(int[]);voidf(int[10]);编译器和函数都不检查数组参数的个数voidf(int*,intsize);voidf(int[],intsize);voidf(int[10],intsize);6.1.8数组参数多维数组参数
intf(intmatrix[][10],introwSize);intf(int(*matrix)[10],introwSize);6.1.9作用域文件域局部域、局部块域类域域操作符:::使程序可以处理被隐藏的外部变量外部变量静态外部变量6.1.10局部域将局部变量的地址传出是一个严重的错误:intf(inta,intb){staticintk; return&a;}静态局部变量寄存器型局部变量6.2.1动态分配空间例6_2_1.cppIntArray中的ia所指的空间是动态分配的,ia本身是静态分配的。在局部域中的对象进入局部域时分配空间,推出时系统自动返回空间。动态分配的空间必须显示地回收空间。6.2.2一个链接表的例子6_2_2_1.cpp6.2.3函数重载两个及两个以上不同的函数共用一个函数名,利用函数的参数表来区别。intmax(int,int);doublemax(double,double);complex&max(complex&,complex);intimax(int,int);doubledmax(double,double);complex&cmax(complex&,complex);6.2.3函数重载参数表和函数名相同的两个函数被认为是重定义。不适合函数重载的情况不同的函数的操作没有类似的地方重载函数的调用完全匹配参数转换引用参数类型的匹配类型必须完全匹配多个参数的调用:6_2_3_7_1.cpp参数的隐含值重载与作用域重载new6.2.4指向函数的指针函数类型指针返回类型(*函数指针名)(参数表);函数名同时也表示指向该函数的指针若voidf(),则f与&f具有相同的类。初始化与赋值voidf(){cout<<"f:"<<endl;}voidg(){cout<<"g:"<<endl;}void(*pf)();voidmain(){ pf=f;pf(); pf=g;pf();}函数指针数组Int(*pfArray[10])(int);例:6_2_4_1.cpp函数指针数组初始化void(*_new_handler)()指向无返回参数无参数的函数的指针。当new分配失败时,测试该指针是否指向了一个函数,如果它为被赋值,则new返回0,否则调用该指针指向的函数。构造函数调用顺序基类的构造函数内部成员对象的构造函数派生类的构造函数析构函数的调用顺序与构造函数调用顺序相反函数重载时参数的传递首先检查是否由完全匹配在检查是否有通过标准转换的匹配通过标准转换后有多种匹配,则报告ambiguous匹配错误。例:6_3_1.cpp全局静态变量全局静态变量的作用外部变量静态局部变量、局部块域例:6_3_3.cpp值参例:6_3_4.cpp#include<iostream.h>voidf(inti){ cout<<i<<endl;}voidmain(){ inti=1;f(i);}8:f(i);004010CFmoveax,dwordptr[ebp-4]004010D2pusheax004010D3call@ILT+15(f)(00401014)004010D8addesp,49:}指针参数#include<iostream.h>voidf(int*i){ cout<<i<<endl;}voidmain(){ inti=1;f(&i);}8:f(i);004010CFleaeax,[ebp-4]004010D2pusheax004010D3call@ILT+35(f)(00401028)004010D8addesp,49:}引用型参数#include<iostream.h>voidf(int&i){ cout<<i<<endl;}voidmain(){ inti=1;f(i);}8:f(&i);004010CFleaeax,[ebp-4]004010D2pusheax004010D3call@ILT+30(f)(00401023)004010D8addesp,49:}用引用返回值例:6_3_5.cpp#include<iostream.h>floattemp;floatfn1(floatr){ temp=r*r*(float)3.14; returntemp;}float&fn2(floatr){ temp=r*r*(float)3.14; returntemp;}voidmain(){ floata=fn1(5.0); //float&b=fn1(5.0); floatc=fn2(5.0); float&d=fn2(5.0); cout<<a<<endl; //cout<<b<<endl; cout<<c<<endl; cout<<d<<endl;}floata=fn1(5.0);fn1r5.0临时变量atemp78.5floatc=fn2(5.0);fn1r5.0临时变量ctemp78.515:floatc=fn2(6.0);00401118push40C00000h0040111Dcall@ILT+20(fn2)(00401019)00401122addesp,400401125moveax,dwordptr[eax]00401127movdwordptr[ebp-8],eaxFloat&d=fn2(5.0);fn1r5.0临时变量d&temptemp78.516:float&d=fn2(7.0);0040112Apush40E00000h0040112Fcall@ILT+20(fn2)(00401019)00401134addesp,400401137movdwordptr[ebp-0Ch],eax7.1类的层次概念层次与复用成员的继承类的两种使用方法:实例化使用继承使用将概念和实现转变成类层次派生类是基类的具体化派生类是基类的延迟定义派生类是基类的组合7.2单继承定义格式class派生类名:[访问控制]基类名{
成员列表}访问控制privateprotectedpublic公有基类基类的公有成员等价于派生类的公有成员。派生类的对象及其成员函数可以访问基类的公有成员。保护基类基类的公有成员等价于派生类的保护成员。派生类的成员函数可以访问基类的公有成员。派生类的对象不可以访问基类的公有成员。私有基类基类的公有成员等价于派生类的私有成员。只有派生类的成员函数可以访问基类的私有成员。部分公开使基类部分公有成员成为派生类的公有成员。base::成员名;在派生类中访问声明不允许对基类成员中私有成员进行访问。例:7_2_1_2.cpp基类性质继承性质派生类性质publicpublicpublicprotectedpublicprotectedprivatepublic不能访问publicprotectedprotectedprotectedprotectedprotectedprivateprotected不能访问publicprivateprivateprotectedprivateprivateprivateprivate不能访问7.2.2成员访问控制公有基类基类成员对基类对象的可见性:公有成员可见,其它不可见。基类成员对派生类的可见性:公有成员和保护成员可见,私有成员不可见。基类成员对派生类对象的可见性公有成员可见,私有成员和保护成员不可见。例:7_2_2.cppclassbase{ private:inti1; protected:intj1; private:intf1();};classdrv:publicbase{ private:inti2; protected:intj2; public:intf2();};Voidmain(){drvd1;}保护基类基类成员对基类对象的可见性:公有成员可见,其它不可见。基类成员对派生类的可见性:公有成员和保护成员可见,私有成员不可见。公有成员和保护成员对派生类的派生类的成员可见基类成员对派生类对象的可见性所有成员都不可见私有基类基类成员对基类对象的可见性:公有成员可见,其它不可见。基类成员对派生类的可见性:公有成员和保护成员可见,私有成员不可见。所有成员对派生类的派生类的成员不可见基类成员对派生类对象的可见性所有成员都不可见7.2.3构造函数参数的传递派生类名::派生类名(派生类参数表):基类名(基类参数表){
派生类初始化代码
}基类没有构造函数或构造函数没有参数基类有构造函数且构造函数都有参数构造函数调用顺序基类的构造函数内部成员对象的构造函数派生类的构造函数析构函数的调用顺序与构造函数调用顺序相反例:7_2_3_1.cpp例子7_2_4_1.cpp7_2_4_2.cpp多继承的概念继承所有基类的成员变量和成员函数inta;intb;intc;inta;intx;inty;inta;intb;intc;inta;intx;inty;intk;多继承的定义格式:Class派生类:访问控制基类[,访问控制基类]{定义体}当有多个同名的继承成员时,可以用域说明符号::来限定。例:7_3_0_1.cpp构造函数的调用顺序基类的构造函数成员对象的构造函数派生类的构造函数例:7_3_0_1.cpp析构函数的调用顺序派生类的析构函数成员对象的析构函数基类的析构函数多重公共基类parentprivate1private2derived_1:virtulparentprivate1private2private3derived_:virtulparent2private1private2private4derived_1_2private1,private2,private3,private4,private12例:7_3_2_1.cpp虚基类虚基类的意义在继承路径上,所有虚基类的成员变量只有一份。虚基类的构造函数必须由最新派生出来的类负责初始化虚基类的构造函数先于非虚基类的构造函数执行。例:若定义classL{...};classA:virtualL{...};classB:virtualL{...};classC:B,A{...};
则在类C中只有一份类L的成员变量。例:7_2_3_2.cpp虚基类parentprivate1private2derived_1:virtualparentprivate1Private2private3derived_2:virtualparentprivate1Private2private4derived_1_2private1,private2,private3,private4,private12例:7_3_2_2.cpp二义性问题(1)classL{public:voidf();};classA{public:intf();};classB:publicL,publicA{public: voidg(){f();}};这个例子中g()的访问f()具有二义性,报告语法错误。可以L::f();或A::f();的形式访问,即用类名加以限制。二义性问题(2)二义性检查在访问控制之前,因此当不同的基类成员中有相同的成员函数名时,就会出现二义性,及时由于访问控制的限制,只有一个成员可见。如果A是B的基类,类A与B都有成员函数f(),则称B::f()支配A:f()。有支配关系的两个名字不会出现二义性。7_3_3_1.cpp7.3.4实例7_3_4_1.cppdata_recStaff:virtualdata_recstudent:virtualdata_recstudent_staffprofessorstudentlast_name;first_namestreet_address;citystate;zip;majorid_number;level;Stafflast_name;first_namestreet_address;citystate;zip;depthourly_wage;运算符重载例:8_2_1.cpp自定义的类的运算往往用函数来实现运算符重载l
运算符重载的目的:扩充语言的功能,即将运算符扩充到用户定义的类型上去。l
除了.、.*、::、?、:其它都可以重载。l
delete、new、指针、引用也可以重载。l
运算符函数可以定义为内联函数。l
用户定义的运算符不改变运算符的优先次序。l
不可以定义系统定义的运算符集之外的运算符。不能改变运算符的的语法结构。双目运算符重载8.2.1双目运算符重载可进行重载的双目运算符:*/%+-<<>><><=>=!=&^|&&||双目运算符重载的声明格式:class类名{类型operator运算符(参数);}双目运算符重载的定义格式: 类型类名::operator运算符(参数);this指针:一个对象调用它的成员函数时,系统会传给它一个指针this,指向对象自己。双目重载时,this指向运算符左边的对象。例:8_2_1_1.cpp友元运算符重载声明:friend类型operator运算符(参数表);定义:类型operator运算符(参数表){……};例:8_2_1_2.cpp成员与友元运算符函数的区别参数个数不同this指针8_2_1_3.cpp8_2_1_4.cpp单目运算符重载不带参数的成员函数8_2_2_2.cpp8_2_2_4.cpp带有一个参数的友元函数8_2_2_1.cpp参数必须是引用不继承=,继承+8_2_2_3.cpp几个特殊的运算符号重载[]重载8_2_3_1.cppX[k]解释为X.operator[](k)()重载8_2_3_1.cppX(arg)解释为X.operator()(arg)虚函数在选择要调用的函数时有几种方法来选择根据参数的特征来选择:同一个类可以用同一个函数名来定义不同的多个函数,它们用参数类型来区分。根据作用域来确定:每个函数都有它的可见的区域。根据类的对象来确定:每个对象都有自己实现的函数的版本。前期联编与后期联编前期联编:在编译时刻就能够确定要调用的函数后期(动态)联编:在运行时刻才能确定要调用的函数为什么需要虚函数一个类中的多个函数的名字可以有相同的名字,但是它们的函数特征(参数类型与个数)必须不同
基类的函数名与派生类的函数可以同名且函数特征(参数类型与个数)完全一致,派生类的对象会调用自己的函数。可以以一个指向基类对象的指针去访问指向派生类的对象,在前期联编的情况下,调用基类的成员函数,只在动态联编的情况下会调用派生类的成员函数。
基类与派生类间指针转换的几条原则指向派生类对象的指针无需进行显示转换就能赋给基类对象:parent*p;derived*d;p=d;基类对象的指针不进行显示转换就不能赋给派生类对象:parent*p;derived*d;d=p;是错误的。基类对象的指针进行显示转换后就能赋给派生类对象:parent*p;derived*d;d=(derived*)p。不能以一个指向派生类对象的指针去访问基类的对象,但可以以一个指向基类对象的指针去访问指向派生类的对象。若没有使用强制类型说明,基类对象指针不能访问在派生类中定义的成员。
指向基类对象的指针可用于指向任何从它派生出来的类对象。8_3_1_4.cpp虚函数的意义告诉编译程序确定一个对象的指针所指的成员函数的问题应等到运行时刻,检查这个指针到底指向哪个对象,基类对象还是派生类对象,调用指针实际所指的对象的成员函数。例:8_3_1_1.cpp例:8_3_1_2.cpp例:8_3_1_3.cpp关于虚函数的一些说明一旦一个函数定义为虚函数,那么无论它传下多少层,都将保持为虚函数。虚函数必须是定义它的类的成员函数。虚函数与派生类中覆盖它的函数有类型匹配,即返回类型、参数个数、类型都相同。虚函数的访问控制规则由它声明时的规则确定。基类的指针可以访问派生类的函数,甚至是派生类的私有函数。8_3_1_5.cpp构造函数不能为虚函数,析构函数可以定义为虚函数。8_3_1_6.cpp含有虚函数的类的实例。基类的构造函数先于派生类的构造函数调用,在对象构造出来之前,派生类中定义的虚函数不可被该类的对象激活。8_3_1_7.cpp纯虚函数:在第一次声明时不提供定义,例如classA{…;virtualvoidf()=0;…};抽象类:一个类如果至少有一个纯虚函数就称为抽象类。抽象类不能实例化,即它不能建立对象。8_3_1_8.cpp8.3.2实例有限状态机:8_3_2_1.cpp定义一个parent类,其它状态定义为parent的子类。指向子类的parent类的指针可以访问子类的转换函数。8_3_2_2.cpp8_3_2_3.cpp作业
一个三口之家,大家都知道父亲会开车、母亲会唱歌。但是父亲还会修电视机,只有家里人知道。小孩既会开车又会唱歌又会修电视机。母亲瞒着任何人在外面做小工补贴家用。此外小孩还会打乒乓球。
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 个人自助循环贷款合同范本
- 东莞抵押合同范本
- 申报课题书怎么写
- 畜牧课题申报书范文
- 原材料海外采购合同范本
- 课题申报书样板
- 光伏承建合同范本
- 公程合同范本
- 申报书课题设计论证
- 全面提升国际化水平的实施方案
- 市场营销-第一章
- 2024年湖北省中考化学真题(解析版)
- 医学课件骨盆骨折的医疗护理-宣教
- 2024肝硬化中医诊疗指南
- 12j912-2常用设备用房
- 农贸市场保安工作总结
- 声学设计音响合同
- 2024年湖南长沙自贸投资发展集团有限公司招聘笔试冲刺题(带答案解析)
- 医院医务人员聘用简单合同范本
- JBT 14714-2024 锂离子电池X射线检测设备(正式版)
- DL-T1362-2014输变电工程项目质量管理规程
评论
0/150
提交评论