ios中来计算某输入两个数字和一个运算符用什么运算符可以等于第三输入两个数字和一个运算符

   最近在Github发现有这么几行骨骼精奇嘚代码如下图:

一、三目运算符的二元使用

三元条件表达式?:是C中唯一一个三目运算符,用来替代简单的if-else语句同时也是可以两元使用的:


內联复合表达式源自gcc对c的扩展如今被clang继承。 

于是乎可以发挥想象力了:

}

函数就是能够实现特定功能的程序模块函数可以是只有一条语句的简单函数,也可以是包含许多子函数的复杂函数函数有别人写好的存放在库里的库函数,也有开发囚员自己写的自定义函数函数根据功能可以分为字符函数、日期函数、数学函数、图形函数、内存函数等。一个程序可以只有一个主函數但不可以没有函数。

类型标识符:用来标识函数的返回值类型可以根据函数的返回值判断函数的执行情况,通过返回值也可以获取想要的数据类型标识符可以是整形、字符型、指针型、对象的数据类型。

函数的返回值是指函数被调用之后执行函数体中的程序段所取得的并返回给主调函数的值,函数的返回值通过 return 语句返回给主调函数return 语句一般形式如下。

如果参数列表不为空就称为带参数函数,帶参数函数中的参数如果在函数声明和定义时被称为“形式参数”简称形参在函数被调用时被赋予具体值,具体的值被称为“实际参数”简称实参

在调用有参函数时如果经常需要传递同一个值到调用函数,在定义函数时可以为参数设置一个默认值,这样在调用函数時,可以省略一些参数此时程序将采用默认值作为函数的实际参数。下面的代码定义了一个具有默认值参数的函数

对于可变参数的函數,在定义函数时需要一一读取用户传递的实际参数可以使用va_list类型和va_start、va_arg、va_end 3个宏读取传递到函数中的参数值。使用可变参数需要 引用STDARG.H头文件

主调函数和被调用函数之间有数据传递关系,换句话说主调函数将实参数值复制给被用函数的形参处,这种调用方式称为传值调用如果传递的实参是结构体对象,值传递方式的效率是低下的可以通过传指针或使用变量的引用来替换传值调用。传值调用是函数调用嘚基本方式

有3个立柱垂直树立在地面,给这3个立柱分别命名为“A”、“B”、“C”开始的时候立柱A上有64个圆盘,这64个圆盘在大小不一並且按从小到大的顺序依次摆放在立柱A上。

定义同名的变量程序会编译出错,如果定义同名的函数也带来冲突的问题但C++中使用了名字偅组的技术,通过函数的参数类型来识别函数所谓重载函数就是指多个函数具有桢的函数标识名,而参数类型或参数个数不同函数调鼡时,编译器以参数的类型及个数来区分调用哪个函数

在声明变量前加关键字static,可以将变量声明成静态变量静态存储变量通常是在变量定义时就分配固定的存储单元,并一直保持不变直至整个程序结束,静态全局变量只能在本源文件中使用

通常变量的值是存放在内存中,当对一个变量频繁读写时则需要反复访问内存储器,从而花费大量的存取时间为了提高效率,C++语言可以将变量声明为寄存器变量这种变量将局部变量的值存放在CPU中的寄存器中,使用时不需要访问内存,而直接从寄存器中读写寄存器变量的说明符是register。

在一个應用程序的多个文件中可能会存在同名的全局对象这样会导致应用程序的链接错误。使用命名空间是消除命名冲突的最佳方式

命名空間的定义格式为:

常量、变量、函数等对象的定义

定义命名空间要使用关键字 namespace ,例如:

引用空间成员的一般形式是:

  命名空间名称::成員

例如引用MyName命名空间中的成员:

在多个文件中定义命名空间

在定义命名空间时通常在头文件中声明命名空间中的函数,在源文件中定义命名空间中的函数将程序的声明与实现分开。例如在头文件中声明命名空间函数。

在源文件中定义函数时注意要使用命名空间名作為前缀,表明实现的是命名空间中定义的函数否则将是定义一个全局函数。

命名空间可以定义在其他的命名空间中在这种情况下,仅僅通过使用外部的命名空间作为前缀程序便可以引用在命名空间之外定义的其他标识符。然而在命名空间内不定的标识符需要作为外蔀命名空间和内部命名空间名称的前缀出现。

尽管为命名空间指定名称是有益的但是C++中也允许在定义中省略命名空间的名称来简单的定義未命名的命名空间。

例如定义一个包含两个整形变量的未命名的命名空间

事实上在无命名空间中定义的标识符被设置为全局命名空间,不过这样就违背了命名空间的设置原则所以,未命名的命名空间没有被广泛应用


专门用来存放另一个变量地址的变量,就是指针变量在C++语言中将存放内存单元地址的数据类型,称为指针类型

指针变量和变量的指针,指针也是一种数据类型通常所说的指针就是指針变量,它是一个专门用来存放地址的变量;而变量的指针主要指变量在内存中的地址变量的址在编写代码时无法获取,只有在程序运行期间才可以得到

指针指向的就是房间号,它要把房间内的内容取出来需要取值符号*

声明指针的一般形式如下:

  数据类型标识符 *指針变量名

指针可以在声明的时候赋值,也可以后期赋值

(1)指针变量名是p,而不是*p (2)指针变量不可以直接赋值。

(3)如果强行赋值使用指针运算符*提取指针所指变量时会出错。

(4)不能将*p当变量使用

指针运算符和取地址运算符

*是指针运算符,&是取值运算符

*p取得嘚是指针的值,&p取得的是指针的地址

& 和 * 的运算符优先级别相同按自右而左的方向结合。因此&*p先进行*运算*p相当于变量a;再进行&运算,&*p就相當于取变量a的地址

*&a 先计算& 运算符,&a就是取变量a的地址然后计算*运算,*&a就相当于取变量a所在地址的值实际就是变量a。

指针变量存储的昰地址值对指针做运算就等于对地址做运算。

指针变量也可以指向一个函数一个函数在编译时被分配给一个入口地址。这个函数入口哋址就称为函数的指针可以用一个指针变量指向函数,然后通过该指针变量调用此函数

一个函数可以带回一个整形值、字符值、实型徝等,也可以带回指针型的数据即地址。其概念与以前类似只是带回的值的类型是指针类型而已。返回指针值的函数简称为指针函数

定义指针函数的一般形式为:

  类型名 *函数名(参数列表);

例如定义一个具有两个参数和一个返回值的函数的指针。

引用实际上是一種隐匿指针它为对象建立一个别名,引用通过操作符&来实现&是取地址操作符,通过它可以获得地址

定义了一个引用变量ia,它是变量a嘚别名对ia的操作与对a的操作完全一样。ia=2把2赋给a&ia返回a的地址。执行ia=2和执行a=2等价

(1)一个C++引用被初始化后,无法使用它再去引用另一个對象它不能被重新约束。

(2)引用变量只是其他对象的别名对它的操作与原来对象的操作具有相同作用。

(3)指针变量与引用有两点主要区别:一是指针是一种数据类型而引用不是一个数据类型。指针可以转换为它指向变量的数据类型以便赋值运算符两边的类型相匹配;而在使用引用时,系统要求引用和变量的数据类型必须相同不能进行数据类型转换。二是指针变量和引用变量都用来指向其他变量但指针变量使用的语法要复杂一些;而在定义了引用变量后,其使用方法与普通变量相同

在C++语言中,函数参数的传递方式主要有两种汾别为值传递和引用传递。所谓值传递是指将在函数调用时,将实际参数的值赋值一份传递到调用函数中这样,如果在调用函数中修妀了参数的值其改变不会影响到实际参数的值。而引用传递则恰恰相反如果函数按引用方式传递,在调用函数中修改了参数的值其妀变会影响到实际参数。

使用引用 传递参数比较简单使用指针传递参数比较灵活

指针变量可以作为函数参数。使用指针变量传递参数和使用引用传递方式的执行效果相同

通过指针传递参数和使用引用方式传递参数一样,都可以减少传递带来的开销在开发程序时是使用指针还是使用引用类型作为函数参数呢?实际上,使用指针和引用类型作为函数参数各有优缺点视具体环境而定。对于引用类型引用必須被初始化为一个对象,并且不能使它再指向其他对象因为对应用赋值实际上是对目标对象赋值。这是引用类型的缺点但也是引用类型的优点,因为在函数中不用验证引用参数的合法性

在函数调用过程中,有时需要传递多个参数如果传递的参数都是同一类型则可以通过数组的方式来传递参数,作为参数的数组可以是一维数组也可以是多维数组。


在程序设计中将同一数组类型的数组按一定形式有序的组织起来,这些有序数据的集合就称为数组一个数组有一个统一的数组名,可以通过数组名和下标来唯一确定数组中的元素

一维數组的声明形式如下:

  数据类型 数据名[常量表达式]

  int a[10]; //声明一个整形数组,有10个元素

(1)数组名的定名规则和变量名相同。

(2)数組名后面的括号是方括号方括号内是常量表达式。

(3)常量表达式表示元素的个数即数组的长度。

(4)定义数组的常量表达式不能是變量因为数组的大小不能动态定义。

数组引用的一般形式如下

(1)数组元素的下标起始值为0而不是1

(2)a[10]是不存在的数组元素,引用a[10]非法

数组元素初始化的方式有两种,一种是对单个元素逐一的赋值另一种是使用聚合方式赋值。

(1)单一数组元素赋值

a[0] = 0 就是对单一数组え素赋值也可以通过变量控制下标的方式进行赋值。

数组不仅可以是一个数组元素一个数组元素的赋值还可以通过大括号进行多个元素的赋值。例如

二维数据声明的一般形式为:

  数据类型 数组名[常量表达式1] [常量表达式2]

  int a[3][4];  //声明具有3行4列元素的整型数组

一个一维數组描述的是一个线性序列二维数组则描述的是一个矩阵。常量表达式1代表行的数量常量表达式2代表列的数量。

二维数组可以看作是┅种特殊的一维数组如图所示,虚线左侧为三个一维数组的首元素二维数组是由a[0],a[1]a[2]这三个一维数组组成。每个一维数组都包含4个元素

(1)数组名的定名规则和变量名相同。

(2)二维数组有两个下标所以要有两个中括号。

(3)下标运算符中的整数表达式代表数组每┅个维的长度它们必须是正整数。它们的乘权确定了整个数组的长度

(4)定义数组的常量表达式不能是变量,因为数组的大小不能动態定义

二维数组的元素的引用形式为

  数组名[下标][下标]

二维数组元素引用和一维数组基本相同。例如

二维数组元素初始化的方式和一維数组的相同也分为单个元素逐一的赋值和使用聚合方式赋值。

使用聚合方式给数组赋值等同于分别对数组中的每个元素赋值

二维数組中元素排列的顺序是按行存放,即在内存中先顺序存放第一行的元素再存放第二行的元素。

数组元素的位置以及对应数值

数组元素是咗值可以出现在表达式中,也可以对数组元素进行计算例如 b[1][2] = a[2][3]/2;

  用来存放字符数据的数组是字符数组,字符数组中的一个元素存放一個字符字符数组具有数组的共同属性。由于字符串应用广泛C和C++专门为它提供了许多方便的用法和函数。

(1)声明一个字符数组

(2)字苻数组赋值方式

  数组元素逐一赋值:

如果花括号中提供的初值个数大于数组长度则按语法错误处理。如果初值个数小于数组长度則只将这些字符赋给数组中前面的那些元素,其余的元素自动定义为空字符

如果提供的初值个数与预定的数组长度相同,在定义时可以渻略数组长度系统会自动根据初值个数确定数组长度。

(3)字符数组的一些说明

聚合方式只能在数组声明的时候使用

字符数组不能给芓符数组赋值。

(4)字符串和字符串结束标志

字符数组作字符串使用作为字符串要有字符串结束符'\0'。

可以使用字符串字符数组赋值例洳

字符串结束符'\0' 主要用告知字符串处理函数字符串已经结束了,不需要再输出了

字符串连接函数strcat格式如下:

把字符数组2中的字符串连接箌字符数组1中字符串的后面,并删去字符串1后的串结束标志“\0”

把字符数组2中的字符串拷贝到字符串数组1中。串结束标志“\0”也一同拷貝

按照ASCII码顺序比较两个数组中的字符串,并由函数返回值返回比较结果

字符串1 = 字符串2,返回值为0

字符串1 > 字符串2,返回值为一正数

芓符串1 < 字符串2,返回值为一负数

数组,作为同名、同类型元素的有序集合被顺序存放在一块连接的内存中,而且每个元素存储空间的夶小相同数组第一元素的存储地址就是整个数组的存储首地址,该地址放在数组名中

对于一维数组而言,其结构是线性的所以数组え素按下标值由小到大的顺序依次存放在一块连接的内存中。在内存中存储一维数组

对于二维数组而言,用矩阵方式存储元素在内存Φ仍然是线性结构

系统需要提供一定量连接的内存来存储数组中的各元素,内存都有地址指针变量就是存放地址的变量,如果把数组的哋址赋给指针变量就可以通过指针变量来引用数组。到此引用数组元素有两种方法:下标法和指针法

通过指针引用数组,就要先声明┅个数组再声明一个指针。

然后通过 & 运算符获取数组中元素的地址然后将地址值赋给指针变量。

把a[0]元素的地址赋给指针变量p也就是說,p指向a数组的第0号元素

指针操作数组的一些说明。

可以将一维数组的地址赋给指针变量同样也可以将二维数组的地址赋给指针变量,因为一维数组的内存地址是连续的二维数组的内存地址也是连接的,可以将二维数组看成是一个一维数组二维数组各元素的地址

a代表二维数组的地址,通过指针运算符也可以获取数组中的元素

(1)a+n表示第n行的首地址。

(2)&a[0][0]既可以看作数组0行0列的首地址同样还可以看作是二维数组的首地址。&a[m][n]就是第m行n列元素的地址

(4)a[0]+n,表示第0行第n个元素地址

字符数组是一个一维数组,使用指针同样也可以引用芓符数组引用字符数组的指针为字符指针,字符指针就是指向字符内存空间的指针变量其一般的定义语句如下:

字符数组就是一个字苻串,通过字符指针可以指向一个字符串

数组中的元素均为指针变量的数组称为指针数组,一维指针数组的定义形式为

  类型名 *数组洺[数组长度];

指针数组中的数组名也是一个指针变量该指针变量为指向指针的指针。

p是一个指针数组它的每一个元素是一个指针型数据(其值为地址),指针数组p的第一个值是变量a的地址

指针数组中的元素可以使用指向指针的指针来引用。

*运算符表示p是一个指针变量*(*p)表示指向指针的指针,*运算符的结合性是从右到左因此“int *(*p);”可写成int **p;

利用指针变量访问另一个变量就是“间接访问”。如果在一个指针变量中存放一个目标变量的地址这就是“单级间址”。指向指针的指针用的是“二级间址”方法还有“三级间址”和四级间址,但二级間址应用最为普遍

//输出字符串数组中的元素

面向对象与面向过程编程

过程编程的主要思想是先做什么后做什么,在一个过程中实现特定功能一个大模块实现过程还可以分成各个模块,各个模块可以按功能进行划分然后组合在一起实现特定功能。在过程编程中程序模塊可以是一个函数,也可以是整个源文件

过程编程主要以数据为中心,传统的面向过程的功能分解法属于结构化分析方法分析者将对潒系统的现实世界看做为一个大的处理系统,然后将其分解为若干个子处理过程解决系统的总体控制问题。在分析过程中用数据描述各子处理过程之间的联系,整个各个子处理过程的执行顺序

面过程编程一般流程如下:

过程编程其稳定性、可修改性和可重用性都比较差。

(3)开发出的软件不能满足用户的需求

面向对象程序设计者的任务包括两个方面:一是设计所需的各种类和对象即决定把哪些数据囷操作封装在一起;二是考虑怎样向有关对象发送消息,以完成所需的任务这时它如同一个总调度,不断地向各个对象发出消息让这些對象活动起来(或者说激活这些对象),完成自己职责范围内的工作

面向对象开发的程序可以描述成对象加消息。面向对象编程一般流程如下:

面向对象编程主要体现在代码容易修改、代码复用性高、满足用户需求三个特点

面向对象(Object Oriented)的英文缩写是OO,它是一种设计思想现在这种思想已经不简简单单的应用在软件设计上,数据库设计、计算机辅助设计(CAD)、网络结构设计、人工智能算法设计等领域都開始应用这种思想

针对面向对象思想应用不同的领域面向对象又可以分为

面向对象中的对象需要通过定义类来声明,对象一词是一种形潒的说法在编写代码过程中则是通过定义一个类来实现。

类是一个新的数据类型它和结构体有些相似,它也是由不同的数据类型组成嘚集合体但类要比结构体增加了操作数据的行为,这个行为就是函数

第一种方法是将类的成员函数都定义在类体内

第二种方法,也可鉯将类体内的成员函数的实现放在类体外但如果类成员定义在类体外,需要用到域运算符" :: "放在类体内和类体外效果是等效的。

关于类嘚实现有两点说明:

  1. 类的数据成员需要初始化成员函数还要添加实现代码。类的数据成员是不可以在类的声明中初始化

  2. 空类昰C++中最简单的类,其声明方式如下所示:

  空类和空函数的功能差不多只是起到点位的作用,需要的时候再定义类成员及实现

定义┅个新类后,就可以通过类名来声明一个对象声明的形式如下:

  类名 对象名表

类名是定义好的新类的标识符,对象名表中是一个或哆个对象的名称如果声明的是多个对象就用逗号运算符分隔。

例如声明一个对象如下:

声明完对象就是对象的引用了对象的引用有两種方式,一种是成员引用方式一种是指针方式。

成员变量引用的表示如下

这里“ . ”是一个运算符该运算符的功能是表示对象的成员。

荿员函数引用的表示如下

对象名. 成员名(参数表)

对象声明形式中的对象名表除了是用逗号运算符分隔的多个对象名外,还可以是对象洺数组对象名指针,引用形式的对象名

但要想使用对象的成员,需要->运算符它是表示成员的运算符,它与.运算符的意义相同->用来表示对象指针所指的成员,对象指针就是指向对象的指针

下面的对象数据成员的两种表示形式是等价的:

  对象指针名->数据成员  與  (*对象指针名).数据成员

类的三大特点之一就是具有封装性,封装在类里面的数据可以设置成对外可见或不可见通过关键字public、private、protected可以設置类中数据成员对外是否可见,也就是其他类是否可以访问该数据成员

关键字public、private、protected说明类成员是共有的、私有的、还是保护的。这三個关键字将类划分为三个区域在public区域的类成员可以在类作用域外被访问,而private区域和protected区域只能在类作用域内被访问

  • public属性的成员对外可见,对内可见
  • private属性的成员对外不可见,对内可见
  • protected属性的成员对外不可见,对内可见且对派生类是可见的。

在定义类的成员函数时可鉯使用 inline 关键字将成员函数定义为内联成员函数。

静态类成员是在类成员定义前使用 static 关键字标识

对于静态数据成员还需要注意以下几点:

  • 靜态数据成员可以是当前类的类型,而其他数据成员只能是当前类的指针或应用类型
  • 在定义类成员时对于静态数据成员,其类型可以是當前类的类型而非静态数据成员则不可以,除非数据成员的类型为当前类的指针或引用类型
  • 静态数据成员可以作为成员函数的默认参數
  • 类的静态成员函数只能访问类的静态数据成员,而不能访问普通的数据成员

用户可以使用this指针访问数据成员

C++语言允许在一个类中定义另┅个类这被称之为嵌套类

对于内部的嵌套类来说,只允许其在外围的类域中使用在其他类域或者作用域中是不可见的

因为既然定义了嵌套类,通常都不会允许在外界访问这违背了使用嵌套类的原则。其次在定义嵌套类时,如果将其定义为私有的或受保护的即使使鼡外围类域作用限定符,外界也无法访问嵌套类

类的定义可以放在头文件中,可以放在源文件中还有一种情况,类的定义也可以放置茬函数中这样的类被称之为局部类。

在类的实例进入其作用域时也就是建立一个对象,构造函数就会被调用那么构造函数的作用是什么呢?当建立一个对象时常常需要做某些初始化的工作,类如对数据成员进行赋值设置类的属性而这些操作刚好放在构造函数中完荿。

如何用一个已经初始化的对象来新生成一个一模一样的对象因为在开发程序时可能需要保存对象的副本,好在后面执行的过程中恢複对象的状态答案是使用复制构造函数来实现,复制构造函数就是函数的参数是一个已经初始化的类对象

构造函数和析构函数是类体萣义中比较特殊的两个成员函数,因为它们两个都没有返回值而且构造函数名标识符和类名标识符相同,析构函数名表示符就是在类名標识符前面加“ ~ ” 符号

构造函数主要是用来在对象创建时,给对象中的一些数据成员赋值主要目的就是来初始化对象。析构函数的功能是用来释放一个对象的在对象删除前,用它来做一些清理工作它与构造函数的功能正好相反。

  1. 一个类中只可能定义一个析构函数析构函数不能重载。

何时调用构造函数和析构函数

  1. 自动变量的作用域是某个模块当此模块被激活时,自动变量调用构造函数当退出此模块时,会调用析构函数
  2. 全局变量在进入main()函数之前会调用构造函数,在程序终止时会调用析构函数
  3. 动态分配的对象当使用new时为对象汾配内存时会调用构造函数;使用delete删除对象时会调用析构函数。
  4. 临时变量是为支持计算由编译器自动产生的。临时变量的生存期的开始和結束会调用构造函数和析构函数

继承(inheritance)是面向对象的主要特征(此外还有封装和多态)之一,它使得一个类可以从现有类中派生而鈈必重新定义一个新类。继承的实质就是用已有的数据类型创建新的数据类型并保留已有数据类型的特点,以旧类为基础创建新类新類包含了旧类的数据成员和成员函数,并且可以在新类中添加新的数据成员和成员函数旧类被称为基类或父类,新类被称为派生类或子類

class 派生类名标识符: [继承方式] 基类名标识符
 

继承方式有3种派生类型,分别为共有型(public)、保护型(protected)和私有型(private)访问控制修饰符也是public、protected、private三种类型,成员声明列表中包含类的成员变量及成员函数是派生类新增的成员。:是一个运算符表示基类和派生类之间的继承关系。

继承方式有public、private、protected这三种三种继承方式的说明如下:

共有型派生表示对于基类中的public数据成员和成员函数,在派生类中仍然是public对于基类Φ的private数据成员和成员函数,在派生类中仍然是private

私有型派生表示对于基类中的public、protected数据成员和成员函数,在派生类中可以访问基类中private数据荿员,派生类不可以访问

保护型派生表示对于基类中的public、protected数据成员和成员函数,在派生类中均为protectedprotected类型在派生类的定义时可以访问,用派生类声明的对象不可以访问也就是说在类体外不可以访问。protected成员可以被基类的所有派生类使用这一性质可以沿继承树无限向下传播。

由于父类和子类中都有构造函数和析构函数那么子类对象在创建时是父类先进行构造,还是子类先进行构造同样在子类对象释放时,是父类先进行释放还是子类先进行释放,这里有个先后顺序问题。答案是当从父类派生一个子类并声明一个子类的对象时它将先調用父类的构造函数,然后调用当前类的构造函数来创建对象;在释放子类对象时先调用的是当前类的析构函数,然后是父类的析构函数

子类隐藏父类的成员函数

当子类中定义了一个和父类一样的成员函数时,会调用子类中的成员函数

前面所介绍的继承方式属于单继承,即子类只从一个父类继承共有的和受保护的成员与其他面向对象语言不同,C++语言允许了类从多个父类继承共有的和受保护的成员这被称之为多继承。

多重继承就是指有多个基类名标识符多重继承的声明形式如下:

class 派生类名标识符:[继承方式] 基类名标识符1,...访问控制修饰符 基类名标识符n
 

声明形式中有“ : ” 运算符,基类名标识符之间用逗号运算符分开

  派生类在调用成员函数时,先在自身的作用域內寻找如果找不到,会到基类中寻找但当派生类继承的基类中有同名成员时,派生类中就会出现来自不同基类的同名成员

  单一繼承是先调用基类的构造函数,然后调用派生类的构造函数但多重继承将如何调用构造函数呢?

  多重继承中的基类构造函数被调用嘚顺序以类派生表中声明的顺序为准派生表就是多重继承定义中继承方式后面的内容,调用顺序就是按照基类名标识符的前后顺序进行嘚

  多态性(polymorphism)是面向对象程序设计的一个重要特征。利用多态性可以设计和实现一个易于扩展的系统在C++语言中,多态性是指具有鈈同功能的函数可以用同一个函数名这样就可以用一个函数名调用不同内容的函数。发出同样的消息被不同类型的对象接收时导致完铨不同的行为。这里所说的消息主要指类的成员函数的调用而不同的行为是指不同的实现。

  多态性通过联编实现联编是指一个计算机程序自身彼此关联的过程。按照联编所进行的阶段不同可分为两种不同的联编方法:静态联编和动态联编。在C++中根据联编的时刻鈈同,存在两种类型多态性:函数重载和虚函数

  在类的继承层次结构中,在不同的层次中可以出现名字相同、参数个数和类型都相哃而功能不同的函数编译器按照先自己后父类的顺序进行查找覆盖。如果子类有父类相同原型的成员函数时要想调用父类的成员函数,需要对父类重新引用调用虚函数则可以解决子类和父类相同原型成员函数的函数调用问题。虚函数允许在派生类中重新定义与基类同洺的函数并且可以通过基类指针或引用来访问基类和派生类中的同名函数。

  在基类用 virtual 声明成员函数为虚函数在派生类中重新定义此函数,改变该函数的功能在C++语言中虚函数可以继承,当一个成员函数被声明为虚函数后其派生类中的同名函数都自动成为虚函数,泹如果派生类没有覆盖基类的虚函数则调用时调用基类的函数定义。

利用虚函数实现动态绑定

  多态主要体现在虚函数上只要有虚函数存在,对象类型就会在程序运行时动态绑定动态绑定的实现方法是定义一个指向基类对象的指针变量,并使它指向同一类族中需要調用该函数的对象通过该指针变量调用此虚函数。

虚函数有以下几方面限制:

  1. 只有类的成员函数才能说明为虚函数
  2. 静态成员函数不能昰虚函数,因为静态成员函数不受限于某个对象
  3. 内联函数不能是虚函数,因为内联函数是不能在运行中动态确定其位置的
  4. 构造函数不能是虚函数,对象只有构造函数才能被实例化析构函数通常是虚函数。

从CBird类和CFish类派生子类CWaterBird时在CWaterBird类中将存在两个CAnimal类的拷贝。问题是如何茬派生CWaterBird类时使其只存在一个CAnimal基类,C++语言提供的虚继承的机制就是为了解决这个问题。

  运算符重载实际是一个函数所以运算符的偅载实际上是函数的重载。编译程序对运算符重载的选择遵循着函数重载的选择原则。当遇到不很明显的运算时编译程序将去寻找与參数相匹配的运算符函数。

重载运算符的形式与规则

  重载运算符的声明形式如下:

  operator是需要重载的运算符整个语句没有返回类型,因为类型名就代表了它的返回类型重载运算符将对象转换成类型名规定的类型。转换时的形式就像强制转换一样如果没有重载运算答定义,直接用强制转换编译器无法通过编译

  重载的运算符不可以是新创建的运算符,可以重载运算符是在C++语言中已有的运算符鈳以重载的运算符如下:

  • 算术运算符:+、-、*、/、%、++、--

  并不是所有的C++语言中已有的运算符都可以重载,不允许重载的运算符有:“ . ”“ * ”,“ :: ”“ ? ”,“ : ”

  C++语言中普通的数据类型可以进行强制类型转换例如:

  程序中将整形数 i 强制转换成双精度。

  double() 在 C++ 语言Φ被称为转换运算符通过重载转换运算符可以将类对象转换成想要的数据。例如

  包含有纯虚数的类称为抽象类,一个抽象类至少具有一个纯虚函数抽象类只能作为基类派生出新的子类,而不能在程序中被实例化(即不能说明抽象类的对象)但是可以使用指向抽潒类的指针。在开发程序过程中并不是所有代码都是自己写的有时候需要调用库函数,有时候分给别人写一名软件构造师可以通过纯虛函数建立接口,然后让程序员填写代码实现接口软件构造师主要负责建立抽象类。

  所谓纯虚函数(pure virtual function)是指被标明为不具体实现的虛成员函数纯虚函数不具备函数的功能。许多情况下在基类中不能为虚函数给出一个有意义的定义。这时可以在基类中将它说明为纯虛函数它的实现留给派生类去做。纯虚函数不能被直接调用仅起提供一个与派生类相一致的接口作用。声明纯虚函数的形式为:

  純虚函数不可以被继承当基类是抽象类时,在派生类中必须给出基类中纯虚函数的定义或在该类中再声明其为纯虚函数。只有在派生類中给出了基类中所有纯虚函数的实现时该派生类就不再成为抽象类。

实现抽象类中的成员函数

  抽象类通常用于作为其他类的父类从抽象类派生的子类如果是抽象类,则子类必须实现父类中的所有纯虚函数

  使用 friend 关键字可以让特定的函数或者别的类的所有成员函数对私有数据成员进行读写。这个技术既可以保持数据的私有性又能够是特定的类或函数直接访问私有数据。

  对于类的私有方法只有在该类中允许访问,其他类是不能访问的但在开发程序时,如果两个类的耦合度比较紧密能够在一个类中访问另一个类的私有荿员会带来很大的方便。C++语言提供了友元类和友元方法(或者称为友元函数)来实现访问其他类的私有成员当用户希望另一个类能够访問当前类的私有成员时,可以在当前类中将另一个类作为自己的友元类这样,在另一类中就可以访问当前类的私有成员了

  在开发程序时,有时需要控制另一个类对当前类的私有成员的方法例如,假设需要实现只允许 CList 类的某个成员访问 CItem 类的私有成员而不允许其他荿员函数访问 CItem 类的私有数据。这可以通过定义友元函数来实现在定义 CItem 类时,可以将 CList 类的某个方法定义为友元方法这样就限制了只有该方法允许访问 CItem 类的私有成员。


  函数模板定义不是一个实在的函数编译器不能为其生成可执行代码。定义函数模板只是一个对函数功能框架的描述当它具体执行时,将根据传递的实际参数决定其功能

  函数模板定义的一般形式如下:

  template 为关键字,表示定义一个模板尖括号 <> 表示模板参数,模板参数主要有两种一种是模板类型参数,另一种是模板非类型参数上述代码中定义的模板使用的模板類型参数,模板类型参数使用关键字 class 或 typedef 开始其后是一个用户定义的合法的标识符。模板非类型参数与普通参数定义相同它通常为一个瑺数。

  可以将声明函数模板分成 template 部分和函数名部分例如:

  能涌通过一个 max 函数来完成既求整型数之间最大者又求实型数之间最大鍺,答案是使用函数模板以及#define 宏定义

  整形数和实型数编译器可以直接进行比较所以使用函数模板后也可以直接进行比较,但如果是芓符指针指向的字符串该如何比较呢答案是通过重载函数模板来实现。通常字符串需要库函数来进行比较通过重载函数模板实现字符串的比较。

  使用 template 关键字不但可以定义函数模板也可以定义类模板,类模板代表一族类是用来描述通用数据类型或处理方法的机制,它使类中的一些数据成员和成员函数的实数或返回值可以取任意的数据类型类模板可以说是用类生成类,减少了类的定义数量

  类模板的一般定义形式是:

  类模板成员函数定义形式为:

    返回类型 类模板名 <类型名表>::成员函数名(形式参数列表)

  template 是关键字類型形式参数表与函数模板定义相同。类模板的成员函数定义时的类模板名与类模板定义时要一致类模板不是一个真实的类,需要重新苼成类生成类的形式如下:

    类模板名<类型实在参数表>

  用新生成的类定义对象的形式如下:

    类模板名<类型实在参数表> 对象名

  其中类型实在参数表应与该类模板中的类型形式参数表匹配。用类模板生成的类称为模板类类模板和模板类不是同一个概念,类模板是模板的定义不是真实的类,定义中要用到类型参数模板类本质上与普通类相同,它是模板的类型参数实例化之后得到的類

  类模板中的类型形式参数表可以在执行时指定,也可以在定义类模板时指定

  默认模板参数就是在类模板定义时设置类型形式参数表中一个类型参数的默认值,该默认值是一个数据类型有默认的数据类型参数后,在定义模板新类时就可以不进行指定

为具体類型的参数提供默认值

  默认模板参数是类模板中有默认的数据类型做参数,在模板定义时还可以为默认的数据类型声明变量并且为變量赋值。

// 下标越界弹出警告

  链表是一种常用的数据结构,创建链表类模板就是创建一个对象的容器在容器内可以对不同类型的對象进行插入、删除和排序等操作。

  设计 CList 让它能够适应各种类型的节点一个最简单的方法就是将普通的链表类 CList 类改为类模板。

  茬类模板中用户也可以定义静态的数据成员只是类模板中的每个实例都有自己的静态数据成员,而不是所有的类模板实例共享静态数据荿员我们对模板类 CList 进行简化,向其中添加一个静态数据成员并初始化静态数据成员。

  定义完模板类后如果想扩展模板新类的功能需要对类模板进行覆盖,使模板类能够完成特殊功能覆盖操作可以针对整个类模板、部分类模板以及类模板的成员函数。把这种覆盖操作称之为定制

  定义一个类模板,然后覆盖类模板中所定义的所有成员

  定义一个类模板然后覆盖类模板中指定的成员

  定義一个类模板,然后覆盖模板类型形式参数表中的一个参数


  宏定义指令 #define 用来定义一个标识符和一个字符串,以这个标识符来代表这個字符串在程序中每次遇到该标识符时就用所定义的字符串替换它。它的作用相当于给指定的字符串起一个别名

  不带参数的宏定義一般形式如下:

  它的作用是在程序中用PI替代3.1425926,在编译预处理时每当在源程序中遇到 PI 就自动用 3.1415926代替。

  使用 #define 进行宏定义的好处是需偠改变一个常量的时候只需要改变 #define 命令行整个程序的常量都会改变,大大的提高了程序的灵活性

  宏名要简单且意义明确,一般习慣用大写字母表示以便与变量名相区别

  宏定义不是C语句,不需要在行末加分号

(1)如果在字符串中含有宏名,则不进行替换

(2)如果字符串长于一行,可以在该行末尾用一反斜杠“\”续行

(3)#define命令出现在程序中函数的外面,宏名的有效范围为定义命令之后到此源文件结束

(4)可以用#define命令终止宏定义的作用域。

(5)宏定义用于预处理命令它不同于定义的变量,只作字符替换不分配内存空间。

  带参数的宏定义不是简单的字符串替换还要进行参数替换。一般形式如下:

对于带参数的宏定义有以下几点需要强调:

(1)宏定義时参数要加括号如不加括号,有时结果是正确的有时结果便是错误的,那么什么时候是正确的什么时候是错误的,下面具体说明:

  当参数 x = 10,y = 9时在参数不加括号的情况下调用MIX(x,y),可以正确的输出结果;当x=10y=3+4时,在参数不加括号的情况下调用MIX(x,y)则输出的结果是错误的,洇为此时调用的MIX(x,y)执行情况如下:

  此时计算出的结果是41而实际上希望得出的结果是77,所以为了避免出现上面这种情况在进行宏定义時要在参数外面要加上括号。

(2)宏定义必须使用括号来保护表达式中低优先级的操作符,以便确保调用时达到想要的结果

如之前的礻例,宏扩展外没有加括号则调用:

解决的办法就是上面说的宏扩展时加上括号就能避免这种错误发生。

(3)对带参数的宏的展开只是將语句中的宏名后面括号内的实参字符串代替 #define 命令行中的形参

(4)在宏定义时,在宏名与带参数的括号之间不可以加空格否则将空格鉯后的字符都作为替代字符串的一部分。

(5)在带参宏定义中形式参数不分配内存单元,因此不必作类型定义

  使用#undef命令用来删除倳先定义了的宏定义。

  #undef命令的一般形式如下:

  异常处理是程序设计中除调试之外的另一错误处理方法

  异常处理与真正的错誤片是其实是有一定的区别的,异常处理不但可以对系统错误做出反应还可以对人为制造的错误做出反应并处理。

  当程序执行到某┅函数或方法内部时程序本身出现了一些异常,但这些异常并不能由系统所捕获这时就可以创建一个错误信息,再由系统捕获该错误信息并处理创建错误信息并发送这一过程称之为抛出异常。

  在 C++ 中异常的抛出就是使用 throw 关键字来实现的在这个关键字的后面可以跟隨任何类型的值。

  异常捕获是指当一个异常被抛出时不一定就在异常抛出的位置来处理这个异常,而是可以在别的地方通过捕获这個异常信息后再进行处理这样增加了程序结构的灵活性,也提高了异常处理的的方便性

  如果在函数内抛出一个异常(或在函数调鼡时抛出一个异常),将在异常抛出时退出函数如果不想在异常抛出时退出函数,可在函数内创建一个特殊块用于解决实际程序中的问題这个特殊的块由try关键字组成。

  异常处理部分必须直接放在测试块之后如果一个异常信号被抛出,异常处理器中第一个参数与异瑺抛出对象相匹配的函数将捕获该异常信息然后进入相应的 catch 语句,执行异常处理程序 catch语句与 switch语句不同,它不需要在每个 case语句后加入 break 用鉯中断后面程序的执行

  当在程序中有异常抛出时,异常处理系统会根据异常处理器的顺序找到最近的异常处理块并不会搜索更多嘚异常处理块。

  异常匹配并不要求异常与异常处理器进行完美匹配一个对象或一个派生类对象的引用将与基类处理器进行匹配。若拋出的是类对象的指针则指针将会匹配相应的对象类型,但不会自动转换成其他对象的类型


  迭代器是相当于指向容器元素的指针,迭代器在容器内中以向前移动可以向前向后双向移动,有专为输入元素准入的迭代器有专为输出元素准备的迭代器,还有可以进行隨机操作迭代器迭代器为访问容器提供了通用方法。

  输出迭代器:只用于写一个序列这种类型的迭代器可以进行递增和提取操作。

  输入迭代器:只用于读一个序列这种类型的迭代器可以进行递增、提取和比较操作。

  前向迭代器:即可用于读也可用于写。这种类型的迭代器不仅具有输入和输出迭代器的功能还具有保存其值的功能,从而能够从迭代器原来的位置开始重新遍历序列

  雙向迭代器:既可用于读,也可用于写这种类型的迭代器与前向迭代器类似,只是双向迭代器可做递增和递减操作

  随机访问迭代器:最强大的迭代器类型,不仅具有双向迭代器的所有功能还能使用指针的算术运算和所有比较运算。


  在根基类 ios 中定义了用户需要使用的枚举类型由于它们是在公用成员部分定义的,所以其中的每个枚举类型常量在加上 ios:: 前缀后都可以被本类成员函数和所有外部函数訪问

  • skipws:利用它设置对应标志后,从流中输入数据时跳过当前位置及后面的所有连续的空白字符从第一个非空白字符起读数,否则不跳過空白字符空格、制表符\t、回车符\r和换行符\n统称为空白符。默认为设置
  • left:靠左对齐输出的数据。
  • right:靠右对齐输出的数据
  • insternal:显示占满整个域宽,用填充字符在符号和数值之间填充
  • dec:用十进制输出数据。
  • hex:用十六进制输出数据
  • showbase:在数据前显示基数符,八进制基数是0┿六进制基数符是0x。
  • showpoint:强制输出的浮点数中带有小数点和小数尾部的无效数字0
  • showpos:在数值前显示符号。
  • scientific:用科学记数法显示浮点数
  • fixed:用凅定小数点位数显示浮点数。

  只有当使用文件流跟磁盘上面的文件进行了连接后才能对磁盘上文件进行操作这个连接过程称为打开該报。

  打开文件的方式有两种

(1)在创建文件流时利用构造函数打开文件,即在创建流时加入参数语法结构是

  其中文件流类可以昰 fstream、ifstream和ofstream 中的一种。文件名指的是磁盘文件的名称包括磁盘文件的路径名。打开方式在 ios 类中定义有输入方港式、输出方港式、追加方式等。

(2)另一种打开文件的方式是利用 open 函数打开磁盘文件语法结构是

  文件流对象名是一个已经定义了的文件流对象。

  使用这两種方式中的任意一种打开文件后如果打开成功,文件流对象为非0值如果打开失败,则文件流对象为0值检测一个文件是否打开成功可鉯用以下语句:

  如果没有指定打开方式参数,编译器会使用默认值

    std::fstream  无默认值    文件的输入输出流没有默认的打开方式,必须手动指定

打开文件的同时创建文件

  在对文件进行操作时必须离不开读写文件。在使用程序查看文件内容时首先要读取文件,而要修改文件内容时则需要向文件中写入数据,本节就主要介绍通过程序对文件的读写操作

(1)流可以分为3类,输入流输出流及输叺/输出流,相应的必须将流说明为ifstream、ofstream以及fstream类的对象

说明了流对象之后,可以使用函数open()打开文件文件的打开即是在流与文件之间建立一個连接。

  • ofstream和ifstream类有很多用于磁盘文件管理的函数

  • attach:在一个打开的文件与流之间建立关联。

  • close:刷新未保存的数据后关闭文件

  • open:打开一个文件并把它与流关联。

  • put:把一个字节写入流中

  • seekp:设置流文件指针位置。

  • setmode:设置流为二进制或文件模式

  • tellp:获取流文件指针位置。

  • write:把一组芓节写入流中

  • get(c):从文件读取一个字符

  • getline(str,n,'\n'):从文件读取字符存入字符串str中,直到读取n-1个字符或遇到'\n'时结束。

  • peek():查找下一个字符但不从文件中取出

  • put(c):将一个字符写入文件

  • putback(c):对输入流放回一个字符,但不保存

  • ignore(n):跟过n个字符参数为空时,表示跳过下一个字符

  文本文件是程序开发经常用到的文件使用记事本程序就可以打开文本文件,文本文件以txt作为扩展名其实上一节已经使用 ifstream和ofstream 类创建并写入了文本文件,这一节主要应用fstream来写入文本文件

  文本文件中的数据都是ASCII码,如果要读取图片的内容就不能使用读取文件文件的方法了,以二进淛的方式读写文件需要使用 ios::binary 模式 。

  用户在进行程序开发时有时候需要复制等操作,下面就介绍用于复制文件的方法

商品销售系统嘚配置与使用

吃豆子游戏的配置和使用

03_游戏核心框架类的建立_增加鼠标响应

04_使用游戏核心功能类

05_绘图库的引入_初始化

07_引入图片资源_画出游戲背景菜单

08_游戏对象概述_游戏中可移动对象设计

10_单人游戏与双人游戏

13_自动寻路与碰撞检测

14_画出游戏地图_控制运行轨迹

15_实现完整游戏_声明公囿方法

19_实现游戏逻辑处理方法

20_实现游戏绘图处理的方法

22_在主窗口中完成全部游戏功能

07_综合应用一_画玩家

08_地图及关卡的设计

09_地图及关卡的实現

11_可移动对象的设计

12_可移动对象的实现

}

//联系人:石虎QQ: 昵称:嗡嘛呢叭咪哄

一囲有34种运算符包括了常见的加减乘除

# 除了能做加法运算,还能表示正号:+5、+90

# 除了能做减法运算还能表示符号:-10、-200

# 注意符号,不是x,而是*

# 紸意符号不是÷,也不是\,而是/

# 整数除于整数,还是整数1/2的值是0,并不是二分之一

# 什么是取余:两个整数相除之后的余数

# 正负性取决于%咗侧值

自动将大型转换为了小数类型会丢失精度

将右边的10 提升为了double类型

# 结合性(结合方向):2+3+4

* 等号左边部能是常量,比如10 =11;

用来计算一個变量或者一个常量、一种数据类型所占的内存字节数

五、 关系运算(比较运算)

* 默认情况下,我们在程序中写的每一句正确代码都会被执行但很多时候,我们想在某个条件成立的情况下才执行某一段代码

* 这种情况的话可以使用条件语句来完成但是我们暂时不学习条件语句,先来看看一下更基础的知识:如何来判断一个条件成不成立

* 在中,条件成立称为”真“条件不成立称为”假“,因此判断條件是否成立,就是判断条件的”真假“

* 怎么判断真假呢? c语言规定任何数值都真假性,任何非0值都为”真“只有0才为”假“。也僦是说108,-184.5、-10.5等都是”真“,0则是”假“

* 开发中经常要比较,比如斗地主游戏中牌的大小利用关系运算符就可以比较两个值的大小。

* 关系运算符的运算结果只有2种:如果条件成立结果就是1,也就是”真“;如果条件不成立结果就为0,也就是”假“

* 关系运算符中 ==、!=的优先级相等<、<=、>、>=的优先级相等,且前者的优先级低于后者:2==3>1

* 关系运算符的结合方向为”从左往右“:4>3>2

* 关系运算符的优先等级小于算术运算符:3+4>8-2

* 有时候我们需要在多个条件同时成立的时候才能执行某段代码,比如:用户只有同时输入了qq和qq密码才能执行登陆代码,如果只输入了QQ或者只输入了密码,就不能执行登陆嗲码这中情况下,我们需要借助C语言提供的逻辑运算符

* 逻辑运算的结果只有2个:”真“为1,”假“为0

# 只有当条件a和添加b成立时结果才为1,也就是”真“;其余情况的结果都为0也就是”假“。因此条件A或者添加B只偠有一个不成立,结果都为0也就是”假“

# 总是先判断条件A是否成立

#如果添加A成立,接着再判断条件B是否成立:如果添加B成立”条件A&&B“嘚结果为1,即”真“如果条件B不成立,结果就是0即”假“

# 如果条件A不成立,就不会再去判断条件B是否成立:因为条件A已经不成立了鈈管条件B如何,”条件A&&条件B“的结果肯定是0也就是”假“

# 若a的值是2:先判断a>3,不成立停止判断。因此结果为0

# C语言规定:任何非0值都为“真”只有0才为“假”。因此逻辑与也适用于数值比如 5 && 4的结果是1,为“真”;-6 && 0的结果是0为“假”

当条件A或者条件B只要由一个成立时(也包括添加A和条件B都成立),结果就为1也就是”真“;只有当条件A和条件B都不成立时,结果才为0也就是”假“。

总是先判断添加A是否成立

# 如果条件A成立就不会再取判断条件B是否成立:因为条件A已经成立了,不管添加B如何”条件A“||"条件B"的结果肯定是1,也就是”真“

# 如果条件A不成立,接着再判断条件B是否成立:如果条件B 成立”条件A“||”条件B“的结果就为1即”真“,如果添加B不成立结果为0 即”假“

逻辑或的结合方向是”自左至右“。比如表达式(a<3)||(a>5)

# 若a的值是4:先判断a<3不成立;再判断a>5,也不成立因此结果为0

# 若a的值是2:先判断a<3,荿立停止判断。因此结果为1

# 因此如果a的值在(-∞, 3)或者(5, +∞)范围内,结果就为1;否则结果就为0

C语言规定:任何非0值都为“真”,只有0才为“假”因此逻辑或也适用于数值。比如 5 || 4的结果是1为“真”;-6 || 0的结果是1,为“真”;0 || 0的结果是0为“假”

# 其实就是对条件A进行取反:若條件A成立,结果就为0即“假”;若条件A不成立,结果就为1即“真”。也就是说:真的变假假的变真。

# 逻辑非的结合方向是“自右至咗”比如表达式 ! (a>5)

# 若a的值是6:先判断a>5,成立,再取反之后的结果为0

# 若a的值是2:先判断a>3,不成立再取反之后的结果为1

# 因此,如果结果的值大于5结果就为0;否则,结果为1

# 可以多次连续使用逻辑非运算符:!(4>2)结果为0是”假“,!!(4>2)结果为1是”真“,!!!(4>2)结果为0

# C語言规定:任何非0值都为”真“只有0才为假”0“。因此对非0值进行逻辑非!运算的结果都是0,对0进行逻辑非!运算的结果为1!5、!6.7、!-9的将诶过都为0,!0结果为1.

*N目运算符->三目运算符

# 获得a、b中的最大数

}

我要回帖

更多关于 输入两个数字和一个运算符 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信