`
- 浏览:
269764 次
- 性别:
- 来自:
沈阳
-
关于C++函数重载及虚函数
学校要搞什么知识点精讲,今天下午临时写了两篇关于C++中函数重载及虚函数的文章。只是打的讲义草稿,所以很多用语都很随便。
函数重载
如何讲函数重载:
What——函数重载是什么?
why——为什么要用函数重载,没有函数重载会怎样?
how——举例说明怎么使用函数重载
*******************************************************************************
能使名字方便使用,是任何程序设计语言的一个重要特征。
当我们创建一个对象(即变量)时,要为这个存储区取一个名字。一个函数就是一个操作的名字。正是靠系统描述各种各样的名字,我们才能写出易于人们理解和修改的程序。象写文章一样,目的在于如何同读者交流。这里就产生了这样一个问题:如何把人类自然语言的有细微差别的概念映射到编程语言中。
通常,自然语言中同一个词可以代表许多种不同的含义,这要依赖上下文来确定。这就是所谓的一词多义,从编程的角度来说就是该词被重载了。所谓重载,从词义上说就是重新载入,用句俗话说就是“换汤不换药”。要学会试着理解这一点,这点非常有用,特别是对于细微的差别。具个例子:
我们可以说“喝可乐,喝酒”。如果非得说成“喝(喝可乐的喝)可乐,喝酒(喝酒的喝)酒”,那将是很愚蠢的,就好像听话的人对指定的动作毫无辨别能力一样。管他和的么事,总不是让液体进入你的体内,至于么样喝,喝了以后起么样的反应,那就是后话了。
然而大多数编程语言要求我们为每个函数设定一个唯一的标识符。如果我们想打印三种不同类型的数据:整型、字符型和实型,我们通常不得不用三个不同的函数名,如p r i n t _ i n t ( )、p r i n t _ c h a r ( )和p r i n t _ f l o a t ( ) ,这些既增加了我们的编程工作量,也给读者理解程序增加了困难。举个吃饭的例子,你桌子上面有三盘菜,你吃第一盘菜要用金筷子,第二盘,要用银筷子,第三盘要用象牙筷子一样,几麻烦,用个方便筷子不是一样的吃了。
说白了,那双方便筷子就是一个函数重载的实例。
在C + +中,还有另外一个原因需要对函数名重载:构造函数。因为构造函数的名字预先由类的名字确定,所以只能有一个构造函数名。但如果我们想用几种方法来创建一个对象时该怎么办呢?例如创建一个类,它可以用标准的方法初始化,也可以从文件中读取信息来初始化,我们就需要两个构造函数,一个不带参数(缺省构造函数),另一个带一个字符串作为参数,以表示用于初始化对象的文件的名字。(例子:两双方便筷子,一双是新的刚那出来的,另一个是高温消毒好了的!但都是方便筷子。)所以函数重载的本质就是允许函数同名。在这种情况下,构造函数是以不同的参数类型被调用的。
重载不仅对构造函数来说是必须的,对其他函数也提供了很大的方便,包括非成员函数。
另外,函数重载意味着,我们有两个库,它们都有一个同名的函数,只要它们的参数不同就不会发生冲突。
我这里讲的主题不是函数重载,而是让大家如何方便是使用“筷子”(函数名)去取用餐桌上的“美味食物”(调用函数)!
函数重载允许多个函数同名(象多种形式的筷子一样),但还有另一种方法使函数调用更方便。如果我们想以不同的方法(象很多不同的手法那筷子一样,左手拿,右手拿)调用同一函数,该怎么办呢?当函数有一个长长的参数列表,而大多数参数每次调用都一样时,书写这样的函数调用会使人厌烦,程序可读性也差。C + +中有一个很通用的作法叫缺省参数。缺省参数就是在用户调用一个函数时没有指定参数值而由编译器插入参数值的参数。(象吃了饭,筷子碗一丢,不想洗碗筷,让你父母来洗一样。)
这样f (“h e l l o”) , f (“h i”, 1 )和f (“h o w d y”, 2 ,‘c’)可以用来调用同一函数。它们也可能是调用三个已重载的函数,但当参数列表相同时,我们通常希望调用同一函数来完成相同的操作。
关于函数重载更深层的说明(编译器)
void print(char);
void print(float);
无论这两个函数是某个类的成员函数还是全局函数都无关紧要。如果编译器只使用函数名字的范围,编译器并不能产生单一的内部标识符,这两种情况下都得用_ p r i n t结尾。(就象一双方便筷子,光看握筷子的手,我们谁都不晓得他夹了什么菜。)
重载函数虽然可以让我们有同名的函数,但这些函数的参数列表应该不一样。所以,为了让重载函数正确工作,编译器要用函数名来区分参数类型名。上面的两个在全局范围定义的函数,可能会产生类似于_ p r i n t _ c h a r和_ p r i n t _ f l o a t的内部名。(看到他夹了么菜了)
因为,为这样的名字分解规定一个统一的标准毫无意义,所以不同的编译器可能会产生不同的内部名。
重载的函数与具有多态性的函数(即虚函数)不同处在于:调用正确的被重载函数实体是在编译期间就被决定了的;而对于具有多态性的函数来说,是通过运行期间的动态绑定来调用我们想调用的那个函数实体。多态性是通过重定义(或重写)这种方式达成的。请不要被重载(overloading)和重写 (overriding)所迷惑。重载是发生在两个或者是更多的函数具有相同的名字的情况下。区分它们的办法是通过检测它们的参数个数或者类型来实现的。
虚函数
什么是虚函数???
虚函数是指一个类中你希望重载的成员函数,当你用一个基类指针或引用指向一个继承类对象的时候,你调用一个虚函数,实际调用的是继承类的版本。
——摘自MSDN
什么是多态???
多态是面向对象程序设计和面向过程程序设计的主要区别之一,何谓多态?一名俗话说:“龙生九子,子子不同”多态就是同一个处理手段可以用来处理多种不同的情况。
这里我们主要讨论虚函数的格式、条件(什么样的函数才叫虚函数)、调用虚函数时的注意事项。
虚函数是成员函数,而且是非static的成员函数。说明虚函数的方法如下:
virtual <类型说明符><函数名>(<参数表>)
其中,被关键字virtual说明的函数称为虚函数。
如果某类中的一个成员函数被说明为虚函数,这就意味着该成员函数在派生类中可能有不同的实现。(例:一句俗话就是“聋子的耳朵——摆设”,就象一个残疾人士,可能他听不见,但不代表他儿子听不见,我们一般把基类叫做“父类”,派生类叫做“子类”。但我们不能说“龙生龙,凤生风,老鼠生儿会打洞”啊!他老爸的耳朵是摆设,但在儿子这里就是接受信息的器官了。)
(1) 与基类的虚函数有相同的参数个数;
(2) 其参数的类型与基类的虚函数的对应参数类型相同;
(3) 其返回值或者与基类虚函数的相同,或者都返回指针或引用,并且派生类虚函数所返回的指针或引用的基类型是基类中被替换的虚函数所返回的指针或引用的基类型的子类型。(就像他老爹不识字,但是他可以让他读大学的儿子来带他看信,读报一样)
一般要求基类中说明了虚函数后,派生类说明的虚函数应该与基类中虚函数的参数个数相等,对应参数的类型相同,如果不相同,则将派生类虚函数的参数的类型强制转换为基类中虚函数的参数类型。
抽象类
带有纯虚函数的类称为抽象类。抽象类是一种特殊的类,它是为了抽象和设计的目的而建立的,它处于继承层次结构的较上层。抽象类是不能定义对象的,在实际中为了强调一个类是抽象类,可将该类的构造函数说明为保护的访问控制权限。
抽象类的主要作用是将有关的组织在一个继承层次结构中,由它来为它们提供一个公共的根,相关的子类是从这个根派生出来的。(例:就是一个手机模具)
抽象类刻画了一组子类的操作接口的通用语义,这些语义也传给子类。一般而言,抽象类只描述这组子类共同的操作接口,而完整的实现留给子类。
抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类没有重新定义纯虚函数,而派生类只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体类了。
一个实例:
class 人()
{public :
//......
void 吃()
{人吃饭;
}
//......
char *Name;
int age;
};
class 狗()
{public :
//......
void 吃()
{狗吃屎;
}
//......
char *Name;
int age;
};
人类、狗类有一些相同的东东,如名字,年纪,吃的动作等,有人想到了为了代码的重用,让人类继承狗类,可是数据的冗余让这个想法完蛋了,所以有人又想出可不可以定义一个这样的类:
这个类界于人类狗类之间,有人类和狗类共有的一些东东,比如年纪,名字,体重什么的,但它是不存在实例的,它的存在意义也是只是为了派生其它类,如人类、狗类,这样可以使系统清淅、。。。。。、、反正好处多多。
在这个世界上根本不存在界于人狗之间的东东,所以这个“人狗之间类”中的“吃”也是没什么意义,你也很难为它的内容下个定义,况且也没必要,所以定义它为纯虚函数,形式为:virtual void 吃()=0; 用来告诉系统:
1、这个函数可以没有函数定义;
2、拥有本函数的类是抽象类;
你可能会说,即然纯虚函数没什么意义,为什么还要它,它的作用是什么呢?
为实现多态作准备!!!
虚函数的作用:
之一: 虚实同型
之二: 相伴永远
之三: 有则用之,无则虚之
关于二义性的单独说明:
什么是二义性?从字面上来说就是产生的歧义,为什么会产生歧义?这里我举个例子:象你到商店去买烟,都是黄鹤楼,有150,24,18三个价位的,都是烟,也就是说烟是他们的基类,而你要买哪包抽呢?跟跟老板将:“拿包黄鹤楼!”他哪知道你买多少钱的烟?这里就产生了二义性!同时也引出了二义性的解决方法!老板就会问你:“买多少钱一包的!”这里你就可以做选择了!但是编译器不会开口问你调用哪个父类的成员函数!所以你要事先说明!(y::gety ())
总结:
用个例子字来总结,函数重载,是静态的多态(静态联编),你可以想象成为,你去餐馆吃饭,吃着不同的菜(不同数量,不同类型的参数),用的是同一双筷子(函数名),自己动手吃,不能指使别人帮你实现功能(自己动手,风记足食)。而虚函数,是动态的多态(动态联编),你则可以想象为,你要么是儿孙满堂的老人或者是有钱的款爷,到饭店吃大餐,自己不动手,而且吃得很讲究,不同的食物要用不同的餐具(不同的对象),而且是使唤别人(子类成员函数实现功能)喂你吃。你只要指使一下(基类指针或引用指向)就OK了。在别人看来,你也是在吃饭(具有相应的功能),但是你根本没有动手,都是要手下的小弟搞定(子类成员函数实现功能)。
分享到:
Global site tag (gtag.js) - Google Analytics
相关推荐
### C++中重载与重写函数的区别及虚函数详解 #### 一、虚函数概述 **1.1 虚函数定义与作用** 在C++中,虚函数是一种特殊的成员函数,它允许子类覆盖父类的行为。虚函数的核心在于实现多态性,即在运行时动态决定...
C++ 虚函数使用 C++ 虚函数是实现多态机制的主要手段。多态机制允许使用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这是一种泛型技术,旨在使用不变的代码来实现可变的算法。 ...
C++是一种强大的面向对象编程语言,它提供了许多高级特性,如虚函数、虚基类、对象实例化以及运算符重载。这些特性使得C++在处理复杂问题时具有极高的灵活性和可扩展性。 首先,我们来探讨**虚函数**。在C++中,虚...
了解并熟练掌握C++的函数重载和覆盖,能够使你的代码更具可读性、灵活性和可维护性,也是成为优秀C++程序员的必备技能。在实际编程中,根据具体需求选择合适的方式,能有效提高程序设计的质量。
在C++编程语言中,虚函数(Virtual Function)是一个关键特性,它允许程序员实现多态性,这是面向对象编程中的核心概念。虚函数使得子类能够重写父类的方法,从而在运行时根据对象的实际类型调用正确的方法,而不是...
总结一下,C++的运算符重载使得我们可以为自定义类型赋予自然的运算行为,而虚函数则确保了多态性,允许通过基类接口访问派生类的功能。在复数类这个例子中,结合这两个概念,我们可以构建出强大而灵活的复数操作库...
如果我们有一个继承自`Base`的子类`Derived`,并且`Derived`重载了`Base`的某些虚函数,那么`Derived`类的虚函数表将包含`Base`的虚函数指针,以及覆盖后的子类虚函数指针。如果子类没有覆盖父类的某个虚函数,那么...
熟悉并掌握继承与派生、虚函数(函数覆盖)、函数重载技术的使用 通过实例了解函数覆盖和函数重载之间的区别 实验前先复习“类与对象”、“派生与继承”、“多态性”部分的内容。 完成以下实验内容。在Visual ...
在C++编程语言中,虚函数(Virtual Functions)和多态(Polymorphism)是面向对象编程的重要特性,它们使得程序具有高度的灵活性和可扩展性。本文将深入探讨这两个概念,结合示例代码进行详细解释。 首先,我们来...
静态多态主要通过函数重载和运算符重载实现,而虚函数实现了动态多态。 六、虚函数表(Vtable) C++编译器为每个含有虚函数的类创建一个虚函数表(Vtable),存储虚函数的地址。对象内部包含一个指向Vtable的指针,...
内容概要:本文深入探讨了C++中面向对象编程(OOP)的关键特性,主要讨论了操作符重载、虚函数与抽象类以及类的访问控制与封装。通过详细的代码示例,解释了如何通过操作符重载实现类对象的常见运算,如何利用虚函数...
10. **多态**:通过虚函数和抽象类实现,是C++面向对象编程的核心特性之一。 通过《C、C++函数手册》,开发者可以深入理解这些函数的工作原理,学习如何正确使用它们,避免常见的陷阱和错误。手册通常还会包含详细...
本文将深入探讨C++的虚函数和Java的抽象函数。 首先,C++的虚函数是通过在函数声明前添加`virtual`关键字来实现的。虚函数的主要作用是在运行时确定调用哪个函数,这种机制称为动态绑定或晚期绑定。例如,如果有...
在C++编程语言中,虚函数(Virtual Functions)和纯虚函数(Pure Virtual Functions)是面向对象编程的重要特性,它们都是实现多态性的方式,但各自有着不同的应用场景和功能特点。下面将详细解释这两个概念以及它们...
在MFC的视图类(CView)中,我们可以通过重载虚函数OnDraw()来定制我们的绘图逻辑。这个函数由框架在需要更新视图时自动调用。 虚函数重载是面向对象编程中的一个重要概念。它允许子类对父类的方法进行重新定义,...
2. 从使用角度,虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调用。构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀。所以构造函数没有必要是虚函数。虚函数的作用在于通过父类的指针...
2. 静态成员函数与虚函数:静态成员函数不属于任何对象,而虚函数则用于实现多态性,是面向对象编程的关键特性。 3. 函数对象(Functors):C++允许自定义类型作为函数的参数,这种类型通常定义了操作符(),可以像...
内容涉及对象的演化、数据抽象、隐藏实现、初始化与清除、函数重载与缺省参数、输入输出流介绍、常量、内联函数、命名控制、引用和拷贝构造函数、运算符重载、动态对象创建、继承和组合、多态和虚函数、模板和包容器...
此外,C++中的模板和面向对象特性也通过函数得以体现,如成员函数、重载运算符、虚函数、多态等。手册可能包含这些高级主题的介绍,帮助开发者深入理解C++的强大功能。模板允许创建泛型代码,而面向对象特性则提供了...
C++函数不仅包含C语言中的函数,还有其特有的成员函数、友元函数、重载函数、虚函数等。C++标准库(STL)提供了一系列高效容器(vector, list, map)和算法(sort, find),这些都以函数模板的形式存在,能够进行...