C++多态性,虚函数,重载,抽象类
来源:互联网 发布:html软件 编辑:程序博客网 时间:2024/06/04 18:28
1,C++多态性,虚函数,重载,纯虚函数,比较有意思,,,,,,
在面向对象的程序中,当不同的对象接受到相同的消息产生不同的动作,这种性质称为多态性。
简单的来说:就是指用一个名字定义不同的函数,这些函数执行不同但有类似的操作,即所谓的同样的接口访问功能不同的函数,从而实现“一个接口,多种方法”
例如:比较两个数的大小,我们可以针对不同的数据类型(整型,浮点型,双精度型),写出多个不同名称的函数来
实现。但是,事实上,由于它们的功能完全相同,所以可以利用多态性来完成这些功能。。。。
int Max(int i, int j){ return i>j?i:j; }float Max(float i, float j){ return i>j?i:j; }鉴于此:如果3,4或着1.2,3.4比较大小的时候,那么Max(3,4)和Max(1.2,3.4)被调用时,编译器会自
判断调用哪一个函数。。。。。。
多态性与联编(编译)
在面向对象的语言中,多态性的实现和联编密不可分。联编(binding,绑定或装配)是将一个标识符名和一个
存储地址联系在一起。。。。一个源程序经过编译,连接,最后生成可执行代码,就是将部分的执行代码联编
在一起的过程。。。。
一般而言,联编方式有两种:静态联编(static binding)和动态联编(dynamic binding)。静态联编是联编在一
个源程序经过编译,连接,成为可执行文件这个过程中的编译阶段完成的,即联编过程是在运行之前完成的,,
动态联编:是指联编在一个源程序经过编译,连接,成为可执行文件的这个过程中的程序执行阶段完成的,即
联编过程是在程序运行时才动态完成的,,,,
C++实现多态性有以下两种情况
1,编译时多态行:通过函数重载,运算符重载,模板重载
2,运行时多态:借助虚函数来实现
虚函数声明:
virtual 函数类型 函数名称 (形式参数表);虚函数的声明只能出现在类声明的函数原型声明中,,,在派生类中可以不显示的声明为虚函数,当调用此成员
函数时,C++系统会自动判断调用哪一个对象的成员函数。。。。
虚函数:单界面多实现
基类中用虚函数定义了一个函数的原型(提供一个界面),那么就提供了公有继承对象的一个公共的界面,而
多个派生类重新定义虚函数的函数体内容(多个实现版本),将基类的指针指向派生类对象,从而达到虚函数
不同实现的目的。。。。。。。。
代码1:
#include <iostream>using namespace std;class shape{ public: float area() { return -1;} };class circle:public shape{ float radius; public: circle(float r) { radius = r;} float area() { return 3.14*radius*radius;} };int main(){ shape obj, *ptr; circle c(3.4); ptr = &obj; cout<<ptr->area()<<endl; ptr = &c; cout<<ptr->area()<<endl; }
程序运行结果:
结果为什么会是这样的呢???我们希望的是求圆的面积啊,,,,,
这是因为在这里只是用到了静态编译,,,,所以前后两次ptr->area()都调用了基类中的area函数,,,,
但是,,,值得注意的是:对于我们的变量,如果有相同的话,那么就会调用派生类中的值。。。。。。。。。
而如果,我们把代码改成了这样:
#include <iostream>using namespace std;class shape{ public: virtual float area()//跟上面的程序相比,只有这里不一样 { return -1;} //关键字virtual说明此函数为虚函数};class circle:public shape{ float radius; public: circle(float r) { radius = r;} float area() //在派生类中,虚函数被重新定义以实现不同的操作。 { return 3.14*radius*radius;} //这种方式称为:函数超越,或者函数覆盖。。。。};int main(){ shape obj, *ptr; circle c(3.4); ptr = &obj; cout<<ptr->area()<<endl; ptr = &c; cout<<ptr->area()<<endl; }
运行结果:
概述:
1,virtual关键字:指示C++编译器对该函数的调用进行动态联编
2,尽管可以用对象名和点运算符的方式调用虚函数,即向对象发送消息tri.area()或者rect.area()。这同样是静态联编
3,只有当访问虚函数是通过基类指针s(或者引用)时才可获得运行时的多态行。。。。
4,在派生类中,虚函数被重新定义时,其函数的原型必须与基类中的函数原型完全相同,,,,,,,,,,,,,
也就是说:什么都一样,就是函数体的实现完全不同
5,必须在继承的体系下实现。。。。。,必须是类的成员函数,普通函数不可能是虚函数。。。。。。
6,虚函数不能是静态成员函数,,,,因为静态成员函数的存储位置说明了它不受限与某个具体的对象。。。。。
7,根据特性,运行时确定,所以内联函数自然而然也就不是虚函数。。。。。。
8,构造函数不能是虚函数,析构函数可以是:因为构造时,对象还是一片未定型的空间。。。。只有在构造完成后,
对象才能成为一个类的名副其实的实例,,,,,、
由此,我们再次简单的总结一下:
虚函数,声明定义一定在基类中,其他的实现可能在派生类中(前提是:函数原型基本一样),这样,通过基类的指
针(引用)跟派生类的对象挂钩,那么调用的就是派生类中的函数了,,,实现了多态。。。。
这里可能跟函数重载有一定关系::
#include <iostream>using namespace std;class base{ public: virtual void func1(); virtual void func2(); virtual void func3(); void fun4(); };class derived:public base{ public: virtual void func1(); //virtual ,虚函数的再次实现 void func2(int x); char func3(); //错误,返回类型不同 void func4(); //普通函数的重载,不是虚函数,,,};void main(){ base d1,*bp; derived d2; bp = &d2; bp->func1(); //调用父类func1() bp->func2(); //调用基类func2() bp->func3(); //调用基类func3() bp->func4(); //调用基类func4() }
虚函数:只能是成员函数,,,,,重载函数:没有要求
虚函数:不同调用通过不同的对象指向或引用
重载函数:根据参数的类型或个数来进行不同的调用。。。。。。
什么函数不能声明为虚函数?
普通函数(非成员函数)、静态成员函数、内联成员函数、构造函数、友元函数
虚函数通过继承方式来体现出多态作用,它必须是基类的非静态成员函数,其访问权限可
以是protected或public,在基类的类定义中定义虚函数的一般形式是:
virtual 函数返回值类型虚函数名(形参表){ 函数体 }
常见的不能声明为虚函数的有:普通函数(非成员函数)、静态成员函数、内联成员函数、构造函数、友元函数。
(1)普通函数不能声明为虚函数。普通函数(非成员函数)只能被重载(overload),不能被重写(override),声明为虚函数也没有什么意思,因此编译器会在编译时绑定函数。
(2) 构造函数不能声明为虚函数。构造函数一般用来初始化对象,只有在一个对象生成之后,才能发挥多态作用。如果将构造函数声明为虚函数,则表现为在对象还没有生成的时候来定义它的多态,这两点是不统一的。另外,构造函数不能被继承,因而不能声明为虚函数。
(3) 静态成员函数不能声明为虚函数。静态成员函数对于每个类来说只有一份代码,所有的对象都共享这份代码,它不归某个对象所有,所以也没有动态绑定的必要性。
(4) 内联(inline)成员函数不能声明为虚函数。内联函数就是为了在代码中直接展开,减少函数调用开销的代价。虚函数是为了在继承后对象能够准确的执行自己的动作,这是不可能统一的。另外,内联函数在编译时被展开,虚函数在运行时才能动态的绑定函数。
(5) 友元函数不能声明为虚函数。友元函数不属于类的成员函数,不能被继承。
设置虚函数时须注意以下几点:
只有类的成员函数才能说明为虚函数;
静态成员函数不能是虚函数;
内联函数不能为虚函数;
构造函数不能是虚函数;
析构函数可以是虚函数,而且通常声明为虚函数。
纯虚函数:
纯虚函数是在基类中说明的虚函数,它在该基类中没有定义具体的操作内容,而在各个派生类中根据实际需要定义
自己的实现。。。。。。
virtual 函数类型 函数名称(函数参数表) = 0;从声明格式看:纯虚函数是在虚函数成员的后面加上“= 0”,纯虚函数是根本没有函数体的,当声明为纯虚函数,那么
为一个类的名副其实的实例,,,,,、
由此,我们再次简单的总结一下:
虚函数,声明定义一定在基类中,其他的实现可能在派生类中(前提是:函数原型基本一样),这样,通过基类的指
针(引用)跟派生类的对象挂钩,那么调用的就是派生类中的函数了,,,实现了多态。。。。
这里可能跟函数重载有一定关系:
基类中就不能给出函数的实现部分,其函数体是由基类的派生类给出。。。。。。。。。。
可以这样说:
有一个动物类,,,,继承有狮子,老虎等,当没有具体的动物时,我们探究它的是不是哺乳动物(作为一个函数)
就没有一点价值
了,所以,此刻的动物类就是一个抽象类,,,,也就是说:动物类这个基类里面没有这个函数的实现,也不能有
那么什么是抽象类(含有纯虚函数的类,抽象类)
class animal{ public: virtual void ISLEG_NUMBER() = 0; };int main(){ animal pig; //错误,抽象类中不能存在对象 animal *p; //正确,可以声明指向动物类(抽象类)的指针 animal f(); //错误,抽象类不能作为函数的返回类型 g(animal); //错误,抽象类不能作为函数的参数类型 }
抽象类,一定不能有对象,,,,,,,,,,,,,,,,,,,,,,,,,,
- C++多态性,虚函数,重载,抽象类
- C++-虚函数,多态性,纯虚函数,抽象类
- 多态性 虚函数 抽象类
- 多态性,虚函数与抽象类
- 多态性:纯虚函数和抽象类
- 【C++】多态性(函数重载与虚函数)
- 【原创】多态性、动态多态性、静态多态性、虚函数、纯虚函数、抽象类总结
- 虚函数,虚析构函数,纯虚函数,多态性,抽象类。
- C/C++ 初学简单笔记 —4— 多态性 虚函数和抽象类
- C#学习日记23---多态性 之 运算符重载、方法重载、抽象类、虚方法
- 多态性,虚函数,纯虚函数,抽象类 .
- 第十三周 任务三 虚函数、多态性和抽象类
- 第十三周【任务一】抽象类,虚函数,多态性。
- 13.1 对虚函数、多态性和抽象类的理解
- 多态性(纯虚函数与抽象类)
- 动物这样叫(多态性、虚函数和抽象类)
- 第十四周--多态性、虚函数和抽象类(1)
- 第十四周--多态性、虚函数和抽象类(2)
- day09 用Myeclipse开发servlet,servlet的生命周期(面试题),ServletContext
- 尝试使用七牛作为图床
- MaterialDesign之RecyclerView学习笔记
- 【MFC-12】VS2010/MFC之列表框控件动态编辑(List Control Edit)
- 删同义词
- C++多态性,虚函数,重载,抽象类
- Fedora23安装fcitx拼音输入法
- 删序列号
- STL中计算排列组合关系的算法
- 如何在你写的应用中跳转到手机系统网络设置页面去,看别人应用代码的时候看到的
- 字符串排列与组合
- Access restriction: The type 'Application' is not API (restriction on required library
- scrollTop点击回滚到顶部
- 【BZOJ1066】【SCOI2007】蜥蜴