多态性

编译时的多态性与运行时的多态性

在面向对象方法中,所谓多态性就是不同对象收到相同信息时,产生不同的行为。在c++程序设计中,即“一个接口,多种方法”

在C++中,多态性的实现和联编这一概念相关,一个源程序经过编译、连接,称为可执行文件的过程即为把可执行代码联编在一起的过程。其中在运行前完成的称为静态联编,又称前期联编,而在运行时完成的称为动态联编,也称后期联编

静态联编支持的多态性称为编译时多态性,也称静态多态性,在c++中通过函数重载和模板实现,动态联编所支持的多态性称为运行时多态性,也称动态多态性,c++通过虚函数实现

运算符重载

运算符重载是通过创建运算符重载函数实现的,运算符重载函数可以是类外定义的普通函数,也可以是类的成员函数或友元函数。

在类外定义的运算符重载函数

c++为运算符重载提供了一种方法,即在进行运算符重载时,必须定义一个运算符重载函数,其名字为operator,后随一个要重载的运算符。

//例:重载'+'号
类名 operator+(类名1 对象名1,类名2 对象名2)
{
......
}
//即可使用以下两种方式调用'+'号重载
对象名1+对象名2;
operator+(对象名1,对象名2);

注意:

1.c++中绝大部分运算符允许重载,但以下运算符例外

 .        成员方位运算符

 .*        成员指针访问运算符

 ::        作用域运算符

 Sizeof     长度运算符

 ?:        条件运算符

2.c++只能对已有的C++运算符进行重载

3.一般来讲,重载的功能应当与原有的功能相类似

4.重载不能改变运算符的操作对象的个数

5.重载不改变运算符原有的优先级

6.重载不能改变运算符原有的结合特性

7.运算符重载函数的参数至少有一个是类对象(或类对象的引用)

8.一般而言,用于类对象的运算符必须重载,但是赋值运算符'='例外,不必用户进行重载

友元运算符重载函数

在c++中,可以把运算符重载函数定义为某个类的友元函数,称为友元运算符重载函数

语法形式

1.在类内部,定义友元运算符重载函数的格式如下

friend 函数类型 operator 运算符(形参表)
{
函数体
}

2.在类外部,定义友元运算符重载函数的格式如下

//在类中,声明友元函数重载函数原型
class X
{
......
friend 函数类型 operator 运算符 (形参表);
......
}
//在类外部,定义友元运算符重载函数
函数类型 operator 运算符 (形参表)
{
函数体
}

X为类名;函数类型指定了友元运算符函数的返回值类型;operator是定义运算符重载函数的关键字;运算符即是要重载的运算符名称

双目运算符重载
class 类名
{
......
friend 函数类型 operator @ (形参表);
......
}
函数类型 operator@(类名1 对象名1,类名2 对象名2)
{
......
}
//即可使用以下两种方式调用重载
对象名1@对象名2;
operator@(对象名1,对象名2);
//@即为运算符
单目运算符重载
class 类名
{
......
friend 函数类型 operator @ (形参表);
......
}
函数类型 operator@(类名 对象名)
{
......
}
//即可使用以下两种方式调用重载
@对象名;
operator@(对象名);
//@即为运算符

说明:

1.运算符重载函数operator@可以返回任何类型,甚至是void类型

2.有的运算符不能定义为友元运算符重载函数,如赋值运算符'=',下标运算符'[]',函数调用运算符'()'等

成员运算符重载函数

在c++中,可以把运算符重载函数定义为某个类的成员函数,称为成员运算符重载函数

语法形式

1.在类内部,定义成员运算符重载函数的格式如下

函数类型 operator 运算符(形参表)
{
函数体
}

2.在类外部,定义友元运算符重载函数的格式如下

//在类中,声明成员运算符重载函数原型
class X
{
......
函数类型 operator 运算符 (形参表);
......
}
//在类外部,定义成员运算符重载函数
函数类型 X:: operator 运算符 (形参表)
{
函数体
}

X为类名;函数类型指定了友元运算符函数的返回值类型;operator是定义运算符重载函数的关键字;运算符即是要重载的运算符名称

双目运算符重载
class 类名
{
......
函数类型 operator @ (形参表);
......
}
函数类型 类名::operator@(类名 对象名)
{
......
}
//即可使用以下两种方式调用重载
对象名1@对象名2;
对象名1.operator@(对象名2);
//@即为运算符
单目运算符重载
class 类名
{
......
函数类型 operator @ ();
......
}
函数类型 类名::operator@()
{
......
}
//即可使用以下两种方式调用重载
@对象名;
对象名.operator@();
//@即为运算符
注意

1.当对类对象与其他类对象使用双目运算符进行运算时,若需要进行随意放置两种类对象,则需要使用友元运算符

"++"和"--"的重载

自增运算符"++"和自减运算符"--"放置在变量前面与后面,其作用是有区别的

对于前缀方式++ob,可以重载为 ob.operator++();operator++(X &ob);

对于后缀方式ob++,可以重载为 ob.operator++(int);operator++(X &ob,int);

调用时,参数int一般被传递给值0

"--"运算符类似

注意:

由于友元运算符重载函数没有this指针,所以不能引用this指针所指向的对象。使用友元函数重载时,应采用对象引用参数传递数据

赋值运算符"="的重载

对任意一类X,若不存在自定义赋值运算符重载,则会自动生成默认的赋值运算符函数

但在某些特殊情况下,如类中存在指针时,默认的赋值运算符重载会产生问题,因此必须显示定义一个赋值运算符重载函数

注意:

类的赋值运算符"="只能重载为成员函数,而不能重载为友元函数,因为会导致赋值语句的混乱

下标运算符"[]"的重载

运算符重载函数只能定义为成员函数,形式如下:

返回类型 类名 :: operator [] (形参)
{
//函数体
}

注意:

形参只能由一个参数

类型转换

系统预定义类型间的转换

类型转换是将一种类型的值转换为另一种类型值。C++提供两种类型转换方式:一种是隐式类型转换;另一种是显式类型转换。

隐式类型转换

隐式类型转换主要遵循以下规则:

1.在赋值表达式A=B的情况下,运算符右端的B的值需转换为A类型后进行赋值

2.char或short类型变量与int类型变量进行运算时,将char或short类型变量转换为int型

3.操作对象不一致时,运算前级别低的类型自动转化为级别高的类型

显式类型转换

1.(int)i //c语言形式

2.int(i) //c++形式

C++保留C的用法,但提倡使用C++形式

类类型与系统预定义类型间的转换

通过转换构造函数进行类型转换

转换构造函数的作用是将一个其他类型的数据转换为它所在类的对象

实现方式:

在类中定义一个只有一个参数的构造函数,参数是待转换类型的数据,在函数体中指定转换的方法

例:

Complex(double r)
{
real=r;imag=0;
}

既可以用以下形式进行类型转换

类名(待转换类型的数据)

注意:

1.转换构造函数的实质也是一种构造函数,遵循构造函数的一般规则,但只有一个参数

2.转换构造函数也可以将另一个类的对象转换为构造函数所在类的对象

通过类型转换函数进行类型转换

类型转换函数的作用是将一个类的对象转换为另一类型的数据

一般格式为

operator 目标类型()
{
函数体
}

其中,目标类型为希望转换成的类型名,既可以是预定义的标准数据类型也可以是其他类的类型

返回值的类型是该函数的目标类型

注意:

1.类型转换函数只能定义为成员函数

2.类型转换函数既没有参数,也不能在函数体前指定类型

3.必须有return语句

4.一个类可以定义为多个类型转换函数

虚函数

虚函数是重载的另一种表现形式,是一种动态的重载方式。

虚函数允许函数调用与函数体之间的联系在运行时才建立,也就是在运行时才决定如何动作,即动态联编。

引入

C++规定:基类对象的指针可以指向它的公有派生的对象,但是当其指向公有派生类对象时,它只能访问派生类从基类继承来的成员,而不能访问公有派生类中定义的成员。

当引用虚函数后,能实现动态调用的功能

定义

虚函数就是在基类中被关键字virtual说明,并在派生类中重新定义的函数。

作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数

虚函数的定义是在基类中进行的,在基类中需要定义为虚函数的成员函数的声明中冠以关键字virtual,方法如下:

virtual 函数类型 函数名 (形参表)
{
函数体
}

在基类中某个成员函数被声明为虚函数后,虚函数即可在一个或多个派生类中重新定义,在重新定义时,包括函数原型、函数名等都必须与基类中原型完全相同。

注意:

1.若在基类中,只声明虚函数原型,则类外定义时,不必加virtual

2.在派生类重新定义虚函数时,关键字virtual可写可不写,但最好写上

3.若派生类没有对基类的虚函数重新定义,则公有派生继承其基类的虚函数,无论被继承多少次,依然保持其虚函数特性

4.虚函数必须为所在类的成员函数,而不是友元函数或静态成员函数

5.只有通过基类指针访问虚函数时才能获得运行时的多态性

虚析构函数

C++中不能声明虚构造函数,但是可以声明虚析构函数

一般格式如下virtual ~类名();

虚函数与重载函数之间的关系

在一个派生类中重新定义基类的虚函数时函数重载的另一种形式,但不同于普通的函数重载

当普通函数重载时,其函数参数或参数类型必须有所不同,返回类型也可以不同

但在重载虚函数时,要求必须完全相同

多重继承与虚函数

多重继承可视为多个单继承的组合,因此多重继承与单继承有相似之处

纯虚函数和抽象类

有时基类会表示一种抽象的概念,它并不与具体的事物相联系。

纯虚函数是一个在基类中说明的虚函数,它在该基类中没有定义,但要求它的派生类中根据需要对它进行定义,或仍然说明为纯虚函数

一般形式如下

virtual 函数类型 函数名(参数表) =0;

格式与一般的虚函数相似,但在后面添加了一个"=0"

声明为纯虚函数后,基类中不再给出函数实现部分

纯虚函数的作用在于为其派生类保留一个函数名,以便派生类重新定义

纯虚函数没有函数体,"=0"仅为表示其为纯虚函数,其不能被调用

若果一个类中至少有一个纯虚函数,则称该类为抽象类

抽象类的规定:

1.抽象类只能作为其他类的基类,不能建立抽象类对象

2.不能用作参数类型,函数返回类型或显式转换的类型。但可以声明指向抽象类的指针变量,该指针可指向它的派生类

3.若抽象类的派生类没有再次声明纯虚函数,则该函数在派生类中依然为纯虚函数,该派生类为抽象类

C++面向对象程序设计学习笔记(6)的更多相关文章

  1. C++面向对象程序设计学习笔记(1)

    基本概念 对象: 面向对象程序设计中,对象是描述其属性的数据以及对这些数据施加的一组操作封装在一起构成的统一体,每个对象都是由数据和操作代码两部分构成的. 类: 面向对象程序设计中,类是具有相同的数据 ...

  2. C++面向对象程序设计学习笔记(7)

    模板与异常处理 模板的概念 模板是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型作为参数. 模板分为函数模板和类模板,它们分别允许用户构造模板类和模板函数 函数模板与模板函数 函数模板实际 ...

  3. C++面向对象程序设计学习笔记(5)

    派生类与继承 概念 继承允许编程者在已有类的基础上创建新的类,可以从一个或者多个已有类中继承函数和数据,并重新定义或者添加新的函数和数据,已有类称为基类或父类,新类称为派生类和子类. 声明 声明一个派 ...

  4. C++面向对象程序设计学习笔记(4)

    类与对象(2) string类 C++不仅向下兼容C的字符表示方法,也声明了一种更方便的字符串类型,即string类. 想要使用string类,必须包括头文件string,即要声明 #include& ...

  5. C++面向对象程序设计学习笔记(3)

    类与对象(1) 结构体与类 结构体的扩充 C++对结构体进行了扩充,它不仅可以含有不同类型的数据,还可以含有函数,结构体的函数可以像访问结构体中的数据一样进行访问. 类的声明 声明类的方法与声明结构体 ...

  6. C++面向对象程序设计学习笔记(2)

    C++在非面向对象方面的扩充 C++向下兼容C语言,因此C语言中的语法在C++中依然成立 输入输出 C++添加了标准输入流对象cin和标准输出流对象cout来进行输入输出, 例: #include&l ...

  7. 20145213《Java程序设计学习笔记》第六周学习总结

    20145213<Java程序设计学习笔记>第六周学习总结 说在前面的话 上篇博客中娄老师指出我因为数据结构基础薄弱,才导致对第九章内容浅尝遏止地认知.在这里我还要自我批评一下,其实我事后 ...

  8. Java程序设计学习笔记(一)

    时间:2015-6-2 23:04 程序员,程序猿,程序媛,码农 -------------------------------------------------------   --Java的应用 ...

  9. JavaScript高级程序设计---学习笔记(二)

    面向对象程序设计1.属性类型.定义多属性.读取属性特性对象的属性在创建时都带有一些特征值,JavaScript通过这些特征值来定义它们的行为.这些特性是为了实现JavaScript引擎用的,因此不能直 ...

随机推荐

  1. [C0] 引言(Introduction)

    引言(Introduction) 欢迎(Welcome) 机器学习是目前信息技术中最激动人心的方向之一.在这门课中,你将学习到这门技术的前沿,并可以自己实现学习机器学习的算法. 你或许每天都在不知不觉 ...

  2. Maven为项目配置仓库

    Maven为项目配置仓库 参考 https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648933541&idx=1&s ...

  3. CentOS下yum方式安装FFmpeg

    FFmpeg一个完整的跨平台解决方案,用于记录,转换和流式传输音频和视频. 文档:https://www.ffmpeg.org/documentation.html FFmpeg安装 1.安装Nux ...

  4. python做中学(七)ord() 函数

    描述 ord() 函数是 chr() 函数(对于8位的ASCII字符串)或 unichr() 函数(对于Unicode对象)的配对函数,它以一个字符(长度为1的字符串)作为参数,返回对应的 ASCII ...

  5. Spring Boot 2.X整合Spring-cache,让你的网站速度飞起来

    计算机领域有人说过一句名言:“计算机科学领域的任何问题都可以通过增加一个中间层来解决”,今天我们就用Spring-cache给网站添加一层缓存,让你的网站速度飞起来. 本文目录 一.Spring Ca ...

  6. Vue中的组件及路由使用

    1.组件是什么        组件系统是 Vue 的一个重要概念,因为它是一种抽象,允许我们使用小型.独立和通常可复用的组件构建大型应用.通常一个应用会以一棵嵌套的组件树的形式来组织: 1.1组件的声 ...

  7. AQS(抽象队列同步器)

    AQS(全称为AbstractQueuedSynchronizer),即抽象队列同步器,它维护了一个volatile int state(代表共享资源)和一个FIFO线程等待队列. state的访问方 ...

  8. 函数的防抖---js

    执行规定一段时间后执行 <input type="text" id="inp" /> <script> var oInp = docum ...

  9. verdaccio启动命令

    1.启动项目 根目录下 verdaccio 2.npm 源管理 nrm 下载 3.nrm 源列表 nrm ls 4.nrm 源增加 nrm add verdaccio http://localhost ...

  10. 【C#】学习笔记(2)委托Delegate相关

    泛型委托类型,同样是根据杨老师的视频来的. 直接上栗子