常量是指在程序中固定不变的值.doc_第1页
常量是指在程序中固定不变的值.doc_第2页
常量是指在程序中固定不变的值.doc_第3页
常量是指在程序中固定不变的值.doc_第4页
常量是指在程序中固定不变的值.doc_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

常量是指在程序中固定不变的值。常量一般有两种表示形式,即符号常量和字面常量。C+ +语言中符号常量的名字就是一个标识符,而字面常量却是一类特殊的单词。字面常量分为整型、浮点型、字符型和字符串型四类。 (单引号) 字符常量的起止标记符 (双引号) 字符串常量的起止标记符# (井字号) 预处理命令的开始标记符1基本类型(1)逻辑型 (2)字符型(3)整型(4)浮点型(5)空值型2基本类型的派生类型short 短类型,缩短字长;long长类型,加长字长;signed有符号类型,取值范围包括正负值;unsigned无符号类型,取值范围只包括正值;。C+ +中的浮点数可以采用尾数加阶码的表示形式,表示的浮点数范围是:单精度型-3.4E383.4E38,但不能超过7位有效数字;双精度型-1.7977E3081.7977E308 ,但不能超过15位有效数字。空值型用关键字void表示,因此又称为void型。空值型的取值为空。C+ +中不存在void型的常量或变量。C+ +语言规定,所有函数说明都必须指明返回值类型,没有返回值的函数应说明为void类型的函数;另外,void类型还可以用来声明一个指针变量。常量是指在程序执行过程中值不改变的量。常量有两种表示形式,即字面常量和符号常量。字面常量的类型是根据书写形式来区分的,它们的类型分别为:整型、浮点型、字符型、字符串型,每个字面常量的字面本身就是它的值。符号常量是一个标识符,在程序中必须遵循“先声明,后使用”的原则。无论字符常量包含一个还是多个字符,每个字符常量只能表示一个字符,当字符常量的一对单引号内多于一个字符时,则将按照一定的规则解释为一个字符。一些特殊的字符,如回车、换行等具有控制功能的字符,或者像单引号、双引号等作为特殊标记使用的字符,就无法直接采用单引号作为起止符号来表示。“转义”字符的概念,其含义是:用反斜线“”引导的下一个字符失去了原来的含义,而转义为具有某种控制功能的字符。另外,还允许用反斜线引导一个具有1至3位的八进制整数或一个以字母x(大、小写均可)作为开始标记的具有1至2位的十六进制整数,对应的字符就是以这个整数作为ASCII码的字符。变量名的命名遵循如下规则:(1) 不能是C+ +关键字;(2)第一个字符必须是字母或下划线;(3)中间不能有空格;(4)变量名中不能包括;,+-之类的特殊符号。实际上变量名中除了能使用26个英文大小写字母和数字外,只能使用下划线“_”。此一个变量名的作用域可能小于其生存期。任何静态变量的生存期将延续到整个程序的终止必须在声明符号常量的同时为其赋初值,系统只允许读取它的值,而不允许再次向它赋值C+ +关键字中的true和false就是系统预先定义的两个符号常量,它们的值分别为1和0可以把符号变量视为一种不允许赋值改变的或只读不写的变量,称其为const变量。C+ +语言中的运算符可以根据其运算分量个数的多少分为单目(或一元)运算符、双目(或二元)运算符和三目(或三元)运算符3类。由算术运算符(包括单目和双目)连接运算分量而组成的式子称为算术表达式!(逻辑非)、&(逻辑与)、|(逻辑或)7位运算C 提供6种位运算符。(1)“&”是按位与运算符,它将两个运算分量的对应二进制位进行与操作。基中,0 和0与得0,0和1与得0,1和0与得0,1和1与得1。(2)“”是按位或运算符,它将两个运算分量的对应二进制位进行或操作。其中,0和0或得0,0和1或得1,1和0或得1,1和1或得1。(3)“”是按位异或运算符,它将两个运算分量的对应二进制位进行异或操作。其中,0和0异或得0,0和1异或得1,1和0异或得1,1和1异或得0。(4)“”是按位右移运算符,由于右移的位数为右边运算分量的值,所以右边运算分量的值必须是一个整数。(5)“”是按位左移运算符,由于左移的位数为右边运算分量的值,所以右边运算分量的值必须是一个整数。(6)“”是按位取反运算符,它将运算分量的对应二进制数的每一位进行取反操作。其中,0取反得1,1取反得0。是C+ +中唯一的三目运算,与其对应的运算符?:称为条件运算符。从左向右依次计算,将表达式n(即最右端的表达式)的值作为整个逗号表达式的值。(3)sizeof运算符使用运算符sizeof可以进行字长提取操作,因此sizeof运算符又称为字长提取符,它的使用格式为:sizeof(运算分量)其中,sizeof为关键字;运算分量既可以是一个类型名,也可以是一个表达式,当作为运算分量的表达式只包含一个变量名时,圆括号()可以省略。字长提取运算的结果为一个整数,该整数表示指定的类型或变量的字节长度,即在内存中占用的字节(Byte)数。(4)圆括号运算符C+ +中不仅将圆括号()归为运算符,而且根据不同的使用方式,可以对圆括号运算符的功能作出以下3种不同的解释:圆括号用于函数调用。其格式为:函数名(实参表)圆括号用于强制类型转换。其格式为:(类型名)表达式圆括号用于类型构造。其格式为:类型名(表达式)类型构造是指使用圆括号中表达式的值来构造一个具有目标数据类型的值,要构造的目标数据类型由类型名指定。数组下标运算符:(下标)。指针运算符:*(取地址)和&(值引用)。动态存储分配运算符:new(分配)和delete(释放)。作用域限定运算符:(类域或全局域)C+ +中并不存在赋值语句和函数调用语句,赋值和函数调用都属于表达式而不是语句。if(条件)语句条件也可以是一条声明语句,其中必须定义一个变量并对它进行初始化。这时,若此变量的值不为0,则条件结果为“真”;若此变量的值为0,则条件结果为“假”。switch(表达式)case常量表达式1:语句序列1switch,case和default为关键字;表达式的值必须属于整型、字符型或枚举型。(1)多个case标号可以共用一组语句序列,以实现对于几个常量值都执行同一操作。switch语句只能对相等关系进行测试,而if语句却可以用关系表达式对一个较大范围内的值进行测试。实际上,while语句是for语句省略掉表达式1和表达式3的特殊情况。dowhile循环与while循环的不同之处在于:dowhile循环的循环体在前,循环条件在后,因此dowhile循环体在任何条件下(即使不满足循环条件)都至少被执行一次。而while循环条件在前,循环体在后,当条件不满足时,循环体有可能一次也不会执行。这一点正是在构造循环结构时决定使用while语句还是dowhile语句的重要依据。break语句只能用在switch语句和循环语句中。在switch语句中,break用来使执行流程跳出switch语句,而继续执行switch后面的语句。在循环语句中,break用来使执行流程无条件地跳出本层循环体。continue语句仅用在循环语句中,它的功能是:结束本次循环,即跳过循环中尚未执行的语句,接着进行下一次是否执行循环的条件判定。(1)return;(2)return表达式;其中,return为关键字,第2种格式中的表达式可以是任何类型的C+ +表达式。return语句只能用在函数体中。在返回类型为void的函数体中,若想跳出函数体,将执行流程转移到调用该函数的位置,应使用return语句的第1种格式。在返回类型不是void的函数体中,应使用return语句的第2种格式,使执行流程转移到调用该函数的位置,并将表达式的值作为函数的返回值。在定义数组时,可以不必给出所有数组元素的初始值,即在定义时部分地初始化数组。(2)二维数组初始化所有在一行中的元素可以用花括号括起来,并且用逗号分隔;对于数字类型数组,如果给定的数值不够,则没有指定数值的元素将初始化为0。此时,至少应有一个值来初始化二维数组。在将多维数组作为函数的形参时,可以不指定该数组中第一维的大小,但是必须指定该数组中其他维的大小。多维数组只可以作为引用参数传递给函数,并且函数不能返回一个数组类型的返回值string类型在ANSI/ISO标准C+ +颁布之前,标准C+ +库并不提供string数据类型。string是一种用户自定义的数据类型,它由C+ +标准库来支持,而不是C+ +语言本身的一部分。在使用strign数据类型之前,需要在程序中包含头文件string并声明其所在的名字空间std。所有元素都是char类型的数组称为字符数组。字符数组有如下特点:数组元素跟一般变量一样可以赋值、比较、计算等。数组下标也是从0N-1(N为数组长度)。字符数组长度可以显式给出,也可以隐式得到。由双引号括起来的字符串常量具有静态字符串数组类型。用字符串对数组初始化时,编译程序以0作为结束这个数组的标志。因此,数组长度至少要比字符串长度多1。strstr(s1,s2);该函数在字符串s1中从左边开始查找字符串s2,若查找成功则返回s2在s1中首次出现的位置,否则返回NULL,如果s2为 ,则返回s1。strlen(s);该函数返回字符串s的长度,即字符串中字符的个数(不包括字符串结尾的 0)。strcmp(s1,s2);该函数比较两个字符串,如果两个字符串相等,返回0。如果字符串s1在字典顺序上比字符串s2大,则返回一个正数;如果比字符串s2小,则返回一个负数。strcat(s1,s2);该函数将字符串s2添加到字符串s1的末端;但并不修改字符串s2。必须确保字符串s1足够大,以便保存它自己的内容和字符串s2中的内容。strcpy(to,from);该函数将from字符串中的内容复制到to字符串中。请记住,构成to的字符串必须足够大,以便保存包含在from中的字符串。否则,to字符串将会溢出,这很可能会导致系统崩溃。一个指针是一个特定类型数据的存储地址,比如一个变量的地址。一元(单目)运算符&用于返回其操作对象的内存地址,其操作对象通常为一个变量名元运算符的*用于返回其操作数所指对象的值,因此,该运算符要求其操作对象为一个指针。使一个指针指向一个具体对象:使用new运算符(或malloc和alloc等函数)给指针分配一个具体空间。将另一个同类型的指针赋给它以获得值。通过&运算符指向某个对象。2)指针运算尽管指针中存放的是变量的地址,但在C+ +中指针只能进行如下运算。指针和整型量可以进行加减若p1,p2为指针,当p1和p2指向同一类型时,可以进行赋值。两个指向同一类型的指针,可进行= =,等关系运算,其实就是地址的比较。两个指向同一数组成员的指针可进行相减,结果为两个指针之间相差元素的个数。注意:两指针不能相加。一般情况下,一个数组元素的下标访问ai等价于相应的指针访问*(a+i)。但特别注意:数组名和指针(变量)是有区别的,前者是常量,即数组名是一个常量指针,而后者是指针变量。因此,尽管我们可写pa=a;但不能写:a=pa;或pa=&a;因为我们不能改变常量的值,也不能取常量的地址。数组名可作为参数进行传递。当将数组名传给函数时,实际上所传递的是数组的开始地址。(即数组第一个元素的地址)为什么要使用指针?简单地说指针运算比数组运算的速度快。此外,使用指针的另外一个原因是在大量数据传递时,使用传递指针要远比传递数据本身效率高的多,如在函数参数传递及函数返回值时。当然,使用指针会给程序带来安全隐患(如指针悬挂问题),同时还使得程序的可读性降低(显然,用数组实现的程序要比用指针实现的程序的可读性要好)。对于字符串常量,可以把它看成是一个无名字符数组,C+ +编译程序会自动为它分配一个空间来存放这个常量,字符串常量的值本身就是指向这个无名字符数组的第一个字符的指针,其类型是字符指针。尽管二维字符数组与字符指针数组在存储形式上不同,但它们在初始化形式以及访问元素方式上却是相同的。采用指针数组的理由是:它可以节省存贮空间,因而通常用来存放不同长度的字符串。例如,如果要保存从标准输入或文件中读入的行,字符指针数组是一个好的选择。因为读入的行可能长短差异很大。int main(int argc,char * argv)或int main(int argc,char * * argv)其中:argc为包含命令本身在内的参数个数。argv为指针数组,数组元素为指向各参数(包含命令本身在内)的指针。类型(*标识符)();例如:int (* fp)();定义了一个指向返回值为整型值的函数的指针fp。与其他类型的指针变量一样,在使用函数指针前必须使它指向一个具体的函数。若要函数指针指向一个具体函数,可通过赋值语句或参数传递。 函数指针=函数名;该赋值语句将使一个函数指针指向一个具体函数(在C+ +中,函数名是作为指向函数的指针值来处理)。函数指针的最大用途是它可以使得一个函数作为其他函数的参数进行传递,扩展了函数的功能。在类型名后跟引用运算符“&”,以及引用名来创建一个引用。引用名就是一个变量名。注意:引用运算符与地址操作符使用相同的符号(即运算符重载),但它们含义不一样。引用运算符只在声明变量的时候使用,它放在类型名后面。(1)引用被创建时,它必须立即被初始化(指针则可以在任何时候被初始化)。(2)一旦一个引用被初始化为一个对象的引用,它就不能再被改变为对另一个对象的引用。(指针则可以在任何时候改变为指向另一个对象。)依据对函数返回值的使用方式,函数的调用方法可分为以下几种:(1)语句调用,这通常用于不带返回值的函数。这种情况下,被调用函数作为一个独立的语句出现在程序中。(2)表达式调用。将被调用函数作为表达式的一部分来进行调用。它适用于被调用函数带有返回值的情况。(3)参数调用。被调用函数作为另一个函数的一个参数进行调用。(注意在函数原型后要有分号)(1)传值传值是将实参值的副本传递(拷贝)给被调用函数的形参。它是C+ +的默认参数传递方式,在此之前的多数函数参数传递都是传值。由于传值方式是将实参的值复制到形参中,因此实参和形参是两个不同的变量,有各自的存储空间,可以把函数形参看作是函数的局部变量。传值的最大好处是函数调用不会改变调用函数实参变量的内容,可避免不必要的副作用。(2)传地址有时我们确实需要通过函数调用来改变实参变量的值,或通过函数调用返回多个值(return语句只能返回一个值),这时仅靠传值方式是不能达到目的。内联函数是真正的函数,只是在调用的时候,内联函数像宏函数一样的展开,所以它没有一般函数的参数压栈和退栈操作,减少了调用开销,因此,内联函数比普通函数有更高的执行效率。在C+ +中使用inline关键字来定义内联函数。inline关键字放在函数定义中函数类型之前。不过,编译器会将在类的说明部分定义的任何函数都认定为内联函数,即使它们没有用inline说明。递归适用以下的一般场合。(1)数据的定义形式按递归定义。(2)数据之间的关系(即数据结构)按递归定义,如树的遍历,图的搜索等。(3)问题解法按递归算法实现,例如回溯法等。使用递归需要注意以下几点:(1)用递归编写代码往往较为简洁,但要牺牲一定的效率。因为系统处理递归函数时都是通过压栈/退栈的方式实现的。(2)无论哪种递归调用,都必须有递归出口,即结束递归调用的条件。(3)编写递归函数时需要进行递归分析,既要保证正确使用了递归语句,还要保证完成了相应的操作。 函数内部定义的局部变量即为自动变量,用于说明自动变量的关键字auto可以省略。形参可以看成是函数的自动变量,作用域仅限于相应函数内。自动变量所使用的存储空间由程序自动地创建和释放。当函数调用时为自动变量创建存储空间,函数调用结束时将自动释放为其创建的存储空间。因此,自动变量随函数的调用而存在并随函数调用结束而消失,由一次调用到下一次调用之间不保存值。(2)外部变量在函数外部定义的变量即为外部变量。外部变量的作用域是整个程序(全局变量)。在C+ +中,程序可以分别放在几个源文件上,每个文件可作为一个编译单位分别编译。外部变量只需在某个文件上定义一次,其他文件若要引用此变量时,应用extern加以说明。(外部变量定义时不必加extern关键字)。在同一文件中,若前面的函数要引用在其后面定义的外部(在函数之外)变量时,也应用extern加以说明。外部变量是由编译程序在编译时给其分配空间,属于静态分配变量,对于数值型(整型、浮点型和字符型)外部变量来说,其有隐含初值0。引进外部变量的原因:其一是只要程序运行外部变量的值是始终存在的;其二是外部变量可以在所有函数间共享。在C+ +中,可以使用外部变量,但是,必须要清楚使用外部变量的副作用。使用外部变量的函数独立性差,通常不能被移植到其他程序中,而且,如果多个函数都使用到某个外部变量,一旦出现问题,就很难发现问题是由哪个函数引起的。在C+ +中,尽量不用或少用外部变量,可使用参数在函数间进行数据的传递。内部静态变量:在局部变量前加上“static”关键字就成为内部静态变量。内部静态变量仍是局部变量,其作用域仍在定义它的函数内。但该类型变量采用静态存储分配,当函数执行完,返回调用点时,该变量并不撤消,其值将继续保留,若下次再进入该函数时,其值仍然存在。内部静态变量有隐含初值0,并且只在编译时初始化一次。外部静态变量:在函数外部定义的变量前加上“static”关键字便成了外部静态变量。外部静态变量的作用域为定义它的文件,即成为该文件的“私有”(private)变量,只有其所在文件上的函数可以访问该外部静态变量,而其他文件上的函数一律不得直接访问该变量,除非通过外部静态变量所在文件上的各种函数来对它进行操作,这也是一种实现数据隐藏的方式。(4)寄存器变量只有自动(局部)变量和函数参数可指定为寄存器存储类,它的作用域与生存期与自动变量完全相同。当指定的寄存器变量个数超过系统所能提供的寄存器数量时,多出的寄存器变量将视同自动变量。只限于int,char,short,unsigned和指针类型可使用register存储类。不能对寄存器变量取地址(即&操作)。使用寄存器变量可以提高存取速度,可将使用频率最高的变量说明成为寄存器变量。一般常用于说明循环变量。(1)变量由编译程序在编译时给其分配存储空间(称为静态存储分配),并在程序执行过程中始终存在,这类变量包括全局变量、外部静态变量和内部静态变量。这类变量的生存周期与程序的运行周期相同,当程序运行时,该变量的生存周期随即存在,程序运行结束,变量的生存周期随即终止。(2)变量由程序在运行时自动给其分配存储空间(称为自动存储分配),这类变量为函数(或块)中定义的自动变量。它们在程序执行到该函数(或块)时被创建,在函数(或块)执行结束时释放所用的空间。分号表示类声明结束。类的成员包括数据成员和成员函数 在类体内定义的成员函数都是内联函数。只有另外一个类的对象,才可以作为该类的成员,即作为该类的成员对象而存在。自身类的对象是不可以作为自身类的成员存在的,但自身类的指针可以。成员函数除了可以定义为内联函数以外,也可以进行重载,可以对其参数设置默认值。(2)构造函数不指定返回类型,它隐含有返回值,由系统内部使用;(3)构造函数可以有一个或多个参数,因此构造函数可以重载;3拷贝构造函数类中有一种特殊的构造函数叫做拷贝构造函数,它用一个已知的对象初始化一个正在创建的同类对象。拷贝构造函数的一般格式如下:拷贝构造函数具有以下特点:(1)也是一种构造函数,因此函数名与类名相同,并且不能指定函数返顺类型。(2)只有一个参数,是对同类的某个对象的引用。(3)每一个类中都必须有一个拷贝构造函数。如果类中没有声明拷贝构造函数,编译器会自动生成一个具有上述形式的公有的拷贝构造函数。6.6 静态成员对于类中的非静态数据成员,每一个类对象都拥有一个拷贝(副本),即每个对象的同名数据成员可以分别存储不同的数值,这是保证每个对象拥有区别于其他对象的特征的需要。而类中的静态成员则是解决同一个类的不同对象之间的数据和函数共享问题的。静态成员的特性是不管这个类创建了多少个对象,它的静态成员都只有一个拷贝(副本),这个副本被所有属于这个类的对象共享。这种共享与全局变量或全局函数相比,既没有破坏数据隐藏的原则,又保证了安全性。1静态数据成员静态数据成员声明时要使用关键字static。静态数据成员在每个类对象中并不占有存储空间,它只是在每个类中分配有存储空间,供所有对象公用。静态数据成员的值对每个对象都是一样的,但它的值可以被任何一个对象更新,从而实现了同一类的不同对象之间的数据共享。静态数据成员具有静态生存期,必须对它进行初始化。静态数据成员初始化的一般格式如下:数据类型类名:静态数据成员名=初始值;在对静态数据成员初始化时应注意:(1)由于在类的声明中仅仅是对静态数据成员进行了引用性声明,因此必须在文件作用域的某个地方对静态数据成员进行定义并初始化,即应在类体外对静态数据成员进行初始化(静态数据成员的初始化与它的访问控制权限无关)。(2)静态数据成员初始化时前面不加static关键字,以免与一般静态变量或对象混淆。(3)由于静态数据成员是类的成员,因此在初始化时必须使用作用域运算符(:)限定它所属的类。2静态成员函数公有的静态数据成员可以直接访问,但私有的或保护的静态数据成员却必须通过公有的接口进行访问,一般将这个公有的接口定义为静态成员函数。使用static关键字声明的成员函数就是静态成员函数,静态成员函数也属于整个类而不属于类中的某个对象,它是该类的所有对象共享的成员函数。静态成员函数可以在类体内定义,也可以在类外定义。当在类外定义时,要注意不能使用static关键字作为前缀。由于静态成员函数在类中只有一个拷贝(副本),因此它访问对象的成员时要受到一些限制:静态成员函数可以直接访问类中说明的静态成员,但不能直接访问类中说明的非静态成员;若要访问非静态成员时,必须通过参数传递的方式得到相应的对象,再通过对象来访问。虽然数据隐藏保证了数据的安全性,但各种形式的数据共享却又不同程度地破坏了数据的安全性。因此,对于既需要共享又需要防止改变的数据应该定义为常量进行保护,以保证它在整个程序运行期间是不可改变的类名const对象名或const类名对象名返回类型成员函数名(参数表)const;6.8 友元在某些情况下,需要在类的外部访问类的私有成员。这时,如果通过公有成员函数进行访问,由于参数传递、类型检查和安全性检查等需要时间上的开销,将影响程序的运行效率。为了解决整个问题,引入了友元。友元可以在类外部直接访问类的私有成员,提高了程序的运行效率。1友元函数友元函数不是当前类的成员函数,而是独立于当前类的外部函数(包括普通函数和其他类的成员函数),但它可以访问该类的所有对象的成员,包括私有成员、保护成员和公有成员。友元函数要在类定义时声明,声明时要在其函数名前加上关键字friend。该声明可以放在公有部分,也可以放在私有部分。友元函数的定主既可以在类内部进行,也可以在类外部进行。2友元类友元除了可以是函数外,还可以是类,即一个类可以作为另一个类的友元,称为友元类。友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。如果这个类有成员对象,要首先执行所有的成员对象的构造函数,当全部成员对象的初始化都完成之后,再执行当前类的构造函数体。析构函数的执行顺序与构造函数的执行顺序相反。基类与派生类之间的关系如下:(1)基类是对派生类的抽象,派生类是对基类的具体化。基类抽取了它的派生类的公共特征,而派生类通过增加信息将抽象的基类变为某种有用的类型,派生类是基类定义的延续。(2)派生类是基类的组合。多继承可以看作是多个单继承的简单组合。(3)公有派生类的对象可以作为基类的对象处理。这一点与类聚集(成员对象)是不同的,在类聚集(成员对象)中,一个类的对象只能拥有作为其成员的其他类的对象,但不能作为其他类对象而使用。缺省的类继承方式是私有继承private。对基类成员和新增成员对象的初始化必须在成员初始化列表中进行。建立派生类对象时,构造函数的执行顺序如下:(1)执行基类的构造函数,调用顺序按照各个基类被继承时声明的顺序(自左向右);(2)执行成员对象的构造函数,调用顺序按照各个成员对象在类中声明的顺序(自上而下);(3)执行派生类的构造函数。如果基类的构造函数定义了一个或多个参数时,派生类必须定义构造函数。对于在不同的作用域中声明的标识符的可见性原则是:如果存在两个或多个具有包含关系的作用域,外层声明的标识符如果在内层没有声明同名标识符,那么它在内层可见;如果内层声明了同名标识符,则外层标识符在内层不可见,这时称内层变量覆盖了外层同名变量。在类的继承层次结构中,基类的成员和派生类新增的成员都具有类作用域,二者的作用范围不同,是相互包含的两个层,派生类在内层。这时,如果派生类定义了一个和某个基类成员同名的新成员(如果是成员函数,则参数表也要相同,参数不同的情况属于重载),派生的新成员就覆盖了外层同名成员,直接使用成员名只能访问到派生类的成员。当一个派生类从多个基类派生,而这些基类又有一个共同的基类,当对该基类中说明的成员进行访问时,可能出现二义性。虚基类就是为了解决这种二义性问题提出来的。虚基类的说明格式如下:class类名:virtual继承方式基类名虚基类的构造函数先于非虚基类的构造函数执行。公有继承时,派生类的对象可以作为基类的对象处理,派生类是基类的子类型。子类型关系使得在需要基类对象的任何地方都可以使用公有派生类的对象来替代,从而可以使用相同的函数统一处理基类对象和公有派生类对象(形参为基类对象时,实参可以是派生类对象),而不必为每一个类设计单独的处理程序,大大提高了程序的效率。它是实现多态性的重要基础之一。(1)公有派生类的对象可以赋值给基类的对象,即用公有派生类对象中从基类继承来的成员,逐个赋值给基类对象的成员。(2)公有派生类的对象可以初始化基类的引用。(3)公有派生类的对象的地址可以赋值给指向基类的指针。编译时的多态性是通过函数重载和模板体现的。利用函数重载机制,在调用同名的函数时,编译系统可根据实参的具体情况确定所调用的是同名函数中的哪一个。利用函数模板,编译系统可根据模板实参以及模板函数实参的具体情况确定所要调用的是哪个函数,并生成相应的函数实例;利用类模板,编译系统可根据模板实参的具体情况确定所要定义的是哪个类的对象,并生成相应的类实例。在成员函数声明的前面加上virtual修饰,即把该函数声明为虚函数。虚函数可以是另一个类的友元函数,但不得是静态成员函数。在C+ +中,一个基类指针(或引用)可以用于指向它的派生类对象,而且通过这样的指针(或引用)调用虚函数时,被调用的是该指针(或引用)实际所指向的对象类的那个重定义版本在派生类中重定义虚函数时,函数名、形参表和返回值类型必须保持不变。虚函数在派生类被重定义后,重定义的函数仍然是一个虚函数,可以在其派生类中再次被重定义无论是虚函数还是实函数,在派生类中被重定义后,原来的函数版本即被隐藏,在通过成员访问运算符 直接调用该函数时,所调用的是重定义版本。但原来的版本依然存在,仍然可以通过在函数名前加域修饰(即:类名:)来调用它们。3虚析构函数析构函数也可以通过virtual修饰而声明为虚函数。虚析构函数与一般虚函数的不同之处在于:(1)重定义函数就是派生类的析构函数,不要求同名。(2)一个虚析构函数的版本被调用执行后,接着就要调用执行基类版本,依次类推,直到调用执行了派生序列的最开始的那个虚析构函数版本为止。通常,只要派生类中包含有虚函数的重定义(从而有可能被多态调用),而且对析函数进行了专门的声明(而不是不做任何声明,从而采用默认的析构函数),其基类的析构函数就应当声明为虚函数,否则就可能出问题。纯虚函数不得声明为内联函数。派生类在重定义一个纯虚函数时,可以继续将之声明为纯虚函数可以在将一个函数声明为纯虚函数的同时,为该函数提供实现版本。换句话说,一个函数是否为纯虚函数,取决于其原形的尾部是否为“=0”,与实现版本的有无没有什么关系。拥有实现版本的纯虚函数仍然有赖于派生类提供重定义版本。纯虚函数的实现版本通常是不完善的版本,但包含了一些共有操作,供各个派生类在重定义函数中调用。派生类在重定义一个纯虚函数时,可以继续将之声明为纯虚函数。另外,纯虚函数不得声明为内联函数。运算符重载是计算机语言固有多态性的体现,是构成计算机语言的基础之一。C把重载的运算符视为特殊的函数,称为运算符函数。运算符重载就是函数重载的一种特殊情况除了.、.*、-*、:、?:这五个运算符外,其他运算符都可以重载不得为重载的运算符函数设置默认值,调用时也就不得省略实参。除了new和delete这两个较为特殊运算符以外,任何运算符如果作为成员函数重载时不得重载为静态函数。=、 、()、-以及所有的类型转换运算符只能作为成员函数重载,而且不能是针对枚举类型操作数的重载。运算符函数的函数名是由运算符前加关键字operator构成的,在声明运算符或调用运算符时都可以用这个名称。gcd是求两个整数的最大公约数的函数,standardize在化简分数时要调用它。=、 、()、-以及所有的类型转换运算符只能作为成员函数重载。如果允许第一操作数不是同类对象,而是其他数据类型,则只能作为非成员函数重开车(如输入输出流运算符和就是这样的情况)。若希望系统在必要时能够利用只需一个实参的构造函数自动对第一操作数进行转换,也应将该运算符作为非成员函数重载;此种情况下,运算符函数的参数应该是非引用参数,否则不能达到所希望的效果。其他情况下一般应作为成员函数重载。template模板形参表声明函数声明其中的模板形参表声明是由一个或多个模板形参组成(如果是多个,需要用逗号隔开)。每个模板形参具有下面几种形式:(1)typename参数名(2)class参数名(3)类型修饰参数名这里的参数名可以是任意的标识符。在这三种形式中,前两种是等价的:在声明模板参数时,关键字typename与cl

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论