c++只有虚函数才能被qt 重写虚函数吗

安全检查中...
请打开浏览器的javascript,然后刷新浏览器
< 浏览器安全检查中...
还剩 5 秒&本帖子已过去太久远了,不再提供回复功能。C++ 虚函数 重载 重写的区别(转) - CSDN博客
C++ 虚函数 重载 重写的区别(转)
版权声明:本文转自
&C&#43;&#43;编程语言是一款应用广泛,支持多种程序设计的计算机编程语言。我们今天就会为大家详细介绍其中C&#43;&#43;多态性的一些基本知识,以方便大家在学习过程中对此能够有一个充分的掌握。
  多态性可以简单地概括为“一个接口,多种方法”,程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念。多态(polymorphism),字面意思多种形状。
  C&#43;&#43;多态性是通过虚函数来实现的,虚函数允许子类重新定义成员函数,而子类重新定义父类的做法称为覆盖(override),或者称为重写。(这里我觉得要补充,重写的话可以有两种,直接重写成员函数和重写虚函数,只有重写了虚函数的才能算作是体现了C&#43;&#43;多态性)而重载则是允许有多个同名的函数,而这些函数的参数列表不同,允许参数个数不同,参数类型不同,或者两者都不同。编译器会根据这些函数的不同列表,将同名的函数的名称做修饰,从而生成一些不同名称的预处理函数,来实现同名函数调用时的重载问题。但这并没有体现多态性。
  多态与非多态的实质区别就是函数地址是早绑定还是晚绑定。如果函数的调用,在编译器编译期间就可以确定函数的调用地址,并生产代码,是静态的,就是说地址是早绑定的。而如果函数调用的地址不能在编译器期间确定,需要在运行时才确定,这就属于晚绑定。
  那么多态的作用是什么呢,封装可以使得代码模块化,继承可以扩展已存在的代码,他们的目的都是为了代码重用。而多态的目的则是为了接口重用。也就是说,不论传递过来的究竟是那个类的对象,函数都能够通过同一个接口调用到适应各自对象的实现方法。
  最常见的用法就是声明基类的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,可以根据指向的子类的不同而实现不同的方法。如果没有使用虚函数的话,即没有利用C&#43;&#43;多态性,则利用基类指针调用相应的函数的时候,将总被限制在基类函数本身,而无法调用到子类中被重写过的函数。因为没有多态性,函数调用的地址将是一定的,而固定的地址将始终调用到同一个函数,这就无法实现一个接口,多种方法的目的了。
笔试题目:
&&&&& 第一个p-&foo()和p-&fuu()都很好理解,本身是基类指针,指向的又是基类对象,调用的都是基类本身的函数,因此输出结果就是1、2。
& & 第二个输出结果就是1、4。p-&foo()和p-&fuu()则是基类指针指向子类对象,正式体现多态的用法,p-&foo()由于指针是个基类指针,指向是一个固定偏移量的函数,因此此时指向的就只能是基类的foo()函数的代码了,因此输出的结果还是1。而p-&fun()指针是基类指针,指向的fun是一个虚函数,由于每个虚函数都有一个虚函数列表,此时p调用fun()并不是直接调用函数,而是通过虚函数列表找到相应的函数的地址,因此根据指向的对象不同,函数地址也将不同,这里将找到对应的子类的fun()函数的地址,因此输出的结果也会是子类的结果4。
  笔试的题目中还有一个另类测试方法。即
&&&&&&&B *ptr = (B *)&a;& ptr-&foo();& ptr-&fun();
  问这两调用的输出结果。这是一个用子类的指针去指向一个强制转换为子类地址的基类对象。结果,这两句调用的输出结果是3,2。
  并不是很理解这种用法,从原理上来解释,由于B是子类指针,虽然被赋予了基类对象地址,但是ptr-&foo()在调用的时候,由于地址偏移量固定,偏移量是子类对象的偏移量,于是即使在指向了一个基类对象的情况下,还是调用到了子类的函数,虽然可能从始到终都没有子类对象的实例化出现。
  而ptr-&fun()的调用,可能还是因为C&#43;&#43;多态性的原因,由于指向的是一个基类对象,通过虚函数列表的引用,找到了基类中fun()函数的地址,因此调用了基类的函数。由此可见多态性的强大,可以适应各种变化,不论指针是基类的还是子类的,都能找到正确的实现方法。
令人迷惑的隐藏规则
本来仅仅区别重载与覆盖并不算困难,但是C&#43;&#43;的隐藏规则使问题复杂性陡然增加。
这里“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual
关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual
关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。
上面的程序中:
(1)函数Derived::f(float)覆盖了Base::f(float)。
(2)函数Derived::g(int)隐藏了Base::g(float),而不是重载。
(3)函数Derived::h(float)隐藏了Base::h(float),而不是覆盖。
C&#43;&#43;纯虚函数
& 纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”&
& virtual void funtion()=0&
二、引入原因
&& 1、为了方便使用多态特性,我们常常需要在基类中定义虚拟函数。&
&& 2、在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。&
& 为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;),则编译器要求在派生类中必须予以重写以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。这样就很好地解决了上述两个问题。
三、相&#20284;概念
&& 1、多态性&
& 指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动作。C&#43;&#43;支持两种多态性:编译时多态性,运行时多态性。&
& a、编译时多态性:通过重载函数实现&
& b、运行时多态性:通过虚函数实现。&
& 2、虚函数&
& 虚函数是在基类中被声明为virtual,并在派生类中重新定义的成员函数,可实现成员函数的动态覆盖(Override)
& 3、抽象类&
& 包含纯虚函数的类称为抽象类。由于抽象类包含了没有定义的纯虚函数,所以不能定义抽象类的对象。
本文已收录于以下专栏:
相关文章推荐
C++中的虚函数(virtual function)&#160;
1.简介&#160;
&#160;&#160;&#160; 虚函数是C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数。假设我们有下面...
对于C++中经常出现的函数名称相同但是参数列表或者返回值不
class fruit
void func()
printf(&fruit\n&);
virtual void vfunc()
printf(&v fruit\n&);...
在别的网站上看到这么一篇文章,对多态的说明很通俗,就转过来.函数重载 如何讲函数重载: What——函数重载是什么? why——为什么要用函数重载,没有函数重载会怎样? how——举例说明怎么使用函数...
本博客(http://blog.csdn.net/livelylittlefish)贴出作者(三二一、小鱼)相关研究、学习内容所做的笔记,欢迎广大朋友指正!&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;...
C++实函数、虚函数、纯虚函数、函数重写
和以前一样,先做好准备g
今天遇到这么个问题,程序中定义了一个借口类,成员函数全是纯虚函数,我写的子类继承了这个接口类,但是报错提示说:无法实例化抽象类!
原因是这样的:子类继承父类时,必须重写父类的纯虚函数,函数名、返回类...
一、重载(overload)指函数名相同,但是它的参数表列个数或顺序,类型不同。但是不能靠返回类型来判断。
(1)相同的范围(在同一个作用域中) ;
(2)函数名字相同;
(3)参数不同;
#include &stdafx.h&
#include &iostream&
class Base
virtual vo...
他的最新文章
讲师:王禹华
讲师:宋宝华
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)博客访问: 820069
博文数量: 165
博客积分: 2853
博客等级: 少校
技术积分: 2275
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: C/C++
纯虚函数在基类中是没有定义的,必须在子类中加以实现,很像java中的接口函数!
引入原因:为了方便使用多态特性,我们常常需要在基类中定义虚函数。
class Cman
virtual void Eat(){……};
void Move();
class CChild : public CMan
virtual void Eat(){……};
//这才是使用的精髓,如果不定义基类的指针去使用,没有太大的意义
p->Eat(); //始终调用CMan的Eat成员函数,不会调用 CChild 的
p->Eat(); //如果子类实现(覆盖)了该方法,则始终调用CChild的Eat函数
//不会调用CMan 的 Eat 方法;如果子类没有实现该函数,则调用CMan的Eat函数
p->Move(); //子类中没有该成员函数,所以调用的是基类中的
引入原因:
1、同“虚函数”;
2、在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。
//纯虚函数就是基类只定义了函数体,没有实现过程定义方法如下
// virtual void Eat() = 0; 直接=0 不要 在cpp中定义就可以了
//纯虚函数相当于接口,不能直接实例话,需要派生类来实现函数定义
//有的人可能在想,定义这些有什么用啊 ,我觉得很有用
//比如你想描述一些事物的属性给别人,而自己不想去实现,就可以定
//义为纯虚函数。说的再透彻一些。比如盖楼房,你是老板,你给建筑公司
//描述清楚你的楼房的特性,多少层,楼顶要有个花园什么的
//建筑公司就可以按照你的方法去实现了,如果你不说清楚这些,可能建筑
//公司不太了解你需要楼房的特性。用纯需函数就可以很好的分工合作了
虚函数和纯虚函数区别
类里声明为虚函数的话,这个函数是实现的,哪怕是空实现,它的作用就是为了能让这个函数在它的子类里面可以被重载,这样的话,这样编译器就可以使用后期绑定来达到多态了
纯虚函数只是一个接口,是个函数的声明而已,它要留到子类里去实现。
protected:
void foo();//普通类函数
virtual void foo1();//虚函数
virtual void foo2() = 0;//纯虚函数
虚函数在子类里面也可以不重载的;但纯虚必须在子类去实现,这就像Java的接口一样。通常我们把很多函数加上virtual,是一个好的习惯,虽然牺牲了一些性能,但是增加了面向对象的多态性,因为你很难预料到父类里面的这个函数不在子类里面不去修改它的实现
虚函数的类用于“实作继承”,继承接口的同时也继承了父类的实现。当然我们也可以完成自己的实现。纯虚函数的类用于“介面继承”,主要用于通信协议方面。关注的是接口的统一性,实现由子类完成。一般来说,介面类中只有纯虚函数的。
错误:带纯虚函数的类叫虚基类,这种基类不能直接生成对象,而只有被继承,并重写其虚函数后,才能使用。这样的类也叫抽象类。
虚函数是为了继承接口和默认行为
纯虚函数只是继承接口,行为必须重新定义////////////////////////////////////////////////////////////////////////////////////  虚基类的初始化与一般多继承的初始化在语法上是一样的,但构造函数的调用次序不同.  派生类构造函数的调用次序有三个原则:  (1)虚基类的构造函数在非虚基类之前调用;  (2)若同一层次中包含多个虚基类,这些虚基类的构造函数按它们说明的次序调用;  (3)若虚基类由非虚基类派生而来,则仍先调用基类构造函数,再调用派生类的构造函数.  在派生类继承基类时,加上一个virtual关键词则为虚拟基类继承,如:  class derive:virtual public base  {  };  虚基类主要解决在多重继承时,基类可能被多次继承,虚基类主要提供一个基类给派生类,如:  class B  {  };  class D1:public B  {  };  class D2:public B  {  };  class C:public D1,public D2  {  };  这里C在D1,D2上继承,但有两个基类,造成混乱。因而使用虚基类,即:  classB  {  };  class D1:virtual public B  {  };  class D2:virtual publicB  {  };  class C:public D1,public D2  (1) 一个类可以在一个类族中既被用作虚基类,也被用作非虚基类。  (2) 在派生类的对象中,同名的虚基类只产生一个虚基类子对象,而某个非虚基类产生各自的子对象。  (3) 虚基类子对象是由最远派生类的构造函数通过调用虚基类的构造函数进行初始化的。  (4) 最远派生类是指在继承结构中建立对象时所指定的类。  (5) 派生类的构造函数的成员初始化列表中必须列出对虚基类构造函数的调用;如果未列出,则表示使用该虚基类的缺省构造函数。  (6) 从虚基类直接或间接派生的派生类中的构造函数的成员初始化列表中都要列出对虚基类构造函数的调用。但仅仅用建立对象的最远派生类的构造函数调用虚基类的构造函数,而该派生类的所有基类中列出的对虚基类的构造函数的调用在执行中被忽略,从而保证对虚基类子对象只初始化一次。  (7) 在一个成员初始化列表中同时出现对虚基类和非虚基类构造函数的调用时,虚基类的构造函数先于非虚基类的构造函数执行。
静态联编:在程序链接阶段就可以确定的调用。动态联编:在程序执行时才能确定的调用。
阅读(76895) | 评论(0) | 转发(11) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。C++ 在继承中虚函数、纯虚函数、普通函数,三者的区别 - 旭东的博客 - 博客园
随笔 - 191, 文章 - 0, 评论 - 199, 引用 - 0
1.虚函数(impure virtual)
  C++的虚函数主要作用是&运行时多态&,父类中提供虚函数的实现,为子类提供默认的函数实现。
  子类可以重写父类的虚函数实现子类的特殊化。
  如下就是一个父类中的虚函数:
virtual void out2(string s)
cout&&"A(out2):"&&s&&
2.纯虚函数(pure virtual)
  C++中包含纯虚函数的类,被称为是&抽象类&。抽象类不能使用new出对象,只有实现了这个纯虚函数的子类才能new出对象。
  C++中的纯虚函数更像是&只提供申明,没有实现&,是对子类的约束,是&接口继承&。
  C++中的纯虚函数也是一种&运行时多态&。
  如下面的类包含纯虚函数,就是&抽象类&:
virtual void out1(string s)=0;
virtual void out2(string s)
cout&&"A(out2):"&&s&&
3.普通函数(no-virtual)
  普通函数是静态编译的,没有运行时多态,只会根据指针或引用的&字面值&类对象,调用自己的普通函数。
  普通函数是父类为子类提供的&强制实现&。
  因此,在继承关系中,子类不应该重写父类的普通函数,因为函数的调用至于类对象的字面值有关。
4.程序综合实例
#include &iostream&
using namespace
virtual void out1()=0;
///由子类实现
virtual ~A(){};
virtual void out2() ///默认实现
cout&&"A(out2)"&&
void out3() ///强制实现
cout&&"A(out3)"&&
class B:public A
virtual ~B(){};
void out1()
cout&&"B(out1)"&&
void out2()
cout&&"B(out2)"&&
void out3()
cout&&"B(out3)"&&
int main()
A *ab=new B;
ab-&out1();
ab-&out2();
ab-&out3();
cout&&"************************"&&
B *bb=new B;
bb-&out1();
bb-&out2();
bb-&out3();
执行结果:

我要回帖

更多关于 纯虚函数重写virtual 的文章

 

随机推荐