[C++]虚函数-同名访问
首先来看一下派生类和基类成员同名事的处理规则:
- 派生类内定义了一个与基类同名的成员,该现象称为同名覆盖,此时,无论派生类内部成员函数还是派生类的对象访问同名成员,如果未加任何特殊标识,则访问派生类中重新定义的同名成员。
- 如果派生类内部成员或派生类的对象需要访问基类继承来的同名函数,则必须在同名函数前加上"基类名::"进行类名限定。
- 如果基类内部成员函数或基类对象访问同名成员,访问的一定是基类的同名成员。
- 用基类的指针,无论是否指向基类对象,都只能访问基类的同名成员。
- 用基类的引用,无论是否是基类对象的别名,都只能访问基类的同名成员。
从4、5两条规则可以看到,无论基类指针指向基类对象还是派生类对象,无论引用是基类对象还是派生类对象的别名,始终调用基类成员。那么,怎样才能使基类指针指向基类对象时调用基类同名成员,指向派生类对象时调用派生类同名成员呢?这就是动态联编所能达到的效果。
为了实现动态联编,首先要将同名函数声明为虚函数。
虚函数可以通过基类指针或引用访问基类和派生类中被声明为虚函数的同名函数。存在继承关系是首要条件,而且派生类一定是以公有方式继承了基类。同名虚函数在基类和派生类中其函数原型必须完全一致,否则无法通过虚函数实现动态多态性。
第一:为什么派生类必须以公有方式继承基类呢?这是赋值兼容规则的使用前提,以下规则反向均不成立。
- 基类对象=公有派生类对象。赋值后的基类对象只能获得基类成员部分,而在派生类中新增加的成员不能被基类对象访问。
- 指向基类对象的指针=公有派生类对象的地址。利用赋值后的指针可以间接访问基类的成员,若要间接访问派生类成员,必须强制转换为派生类类型指针访问。
- 指向基类对象的指针=指向公有派生类对象的指针。
- 基类的引用=公有派生类对象,即派生类对象可以初始化基类的引用。赋值后的引用只可以访问基类成员,无法访问派生类新增成员,因为无法对引用进行强制类型转换。
一般来说,可以将类层次中具有共性的成员函数声明为虚函数,而个性的函数没有必要声明为虚函数。但以下情况是特例:
- 静态成员函数不能声明为虚函数。因为静态成员函数不属于某一个对象,没有多态性。
- 内联函数不恩能够声明为虚函数。因为内联函数的执行代码是明确的,没有多态性的特征。
- 构造函数不能是虚函数。因为构造函数声明为虚函数是完全没有意义的。
- 析构函数往往被声明为虚函数。
如果基类的析构函数声明为虚函数,则该类所有派生类的析构函数也自动成为虚函数而无需显式声明。在这种情况下,由于实施多态性是将基类的指针指向派生类的对象,若果删除该指针,则会调用该指针指向的派生类的析构函数,而派生类的析构函数又自动调用基类的析构函数,这样整个派生类的对象被完全释放。如果析构函数不是虚函数,则编译器实施静态绑定,在删除基类指针时,只调用指针所属基类的析构函数而不调用派生类的析构函数,这会导致析构不完全。所以当派生类中存在指针数据成员,又通过该指针进行了动态空间申请时,将析构函数声明为虚函数是非常有必要的。
第二:为什么同名虚函数在基类和派生类中其函数原型必须完全一致?一个函数在基类和公有派生类中拥有相同的函数名,但函数返回值类型不同,或者是形式参数表不同,即使在基类中被声明为虚函数,也不具备多态性。这种情况下,基类中的函数无虚函数特性,当做普通函数使用,而在派生类中存在同名函数就是本文开始讲到的同名覆盖现象,无法通过基类的指针或引用实现动态多态性。
下面的几条面试题可以巩固本文的知识。
1.题目是问下面的C++代码输出是什么?(阿里巴巴)
class Base
{
public:
int Bar(char x) { return (int)x;}
virtual int Bar(int x) { return (2*x);}
}; class Derived : public Base
{
public:
int Bar(char x) { return (int)(-x);}
int Bar(int x) { return (x/2);}
}; void main()
{
Derived Obj;
Base* pObj=&Obj;
printf("%d,",pObj->Bar((char)(100)));
printf("%d,",pObj->Bar(100));
}
答案是:100,50
2. What's the output of the following code?(微软)
class A
{
public:
virtual void f()
{
cout << "A::f()" << endl; }
void f() const
{
cout << "A::f() const" << endl;
}
}; class B : public A
{
public:
void f()
{
cout << "B::f()" << endl;
}
void f() const
{
cout << "B::f() const" << endl;
}
};
void g(const A * a)
{
a->f();
} int main()
{
A * a = new B();
a->f();
g(a);
delete a;
}
答案是:B::f()
A::f() const
转载请注明出处:http://www.cnblogs.com/Rosanna/p/3346046.html
[C++]虚函数-同名访问的更多相关文章
- C++之虚函数和多态
干货较多-需要自己深思理解: C++支持两种多态性: 1.编译时多态性(静态绑定-早绑定) 在程序编译阶段即可以确定下来的多态性 通过使用 重载机制(重载函数)实现 (模板)http://blog.c ...
- C++中虚函数功能的实现机制
要理解C++中虚函数是如何工作的,需要回答四个问题. 1. 什么是虚函数. 虚函数由于必须是在类中声明的函数,因此又称为虚方法.所有以virtual修饰符开始的成员函数都成为虚方法.此时注意是vir ...
- c++ 一般虚函数
类图: 代码: #include <iostream> using namespace std; class CFather //父类 { public: virtual void dis ...
- virtual之虚函数,虚继承
当类中包含虚函数时,则该类每个对象中在内存分配中除去数据外还包含了一个虚函数表指针(vfptr),指向虚函数表(vftable),虚函数表中存放了该类包含的虚函数的地址. 当子类通过虚继承的方式从父类 ...
- 【C++】虚函数的实现机制
一.什么是虚函数? 虚函数是在类中由virtual关键字声明的成员函数,并且每一个含有虚函数的类都至少有一个与之对应的虚函数表,其中存放着该类所有虚函数对应的函数指针 在基类中进行如下定义: virt ...
- C++——多态性 与 虚函数
多态性 多态性是面向对象程序设计的关键技术之一.若程序设计语言不支持多态性,不能称为面向对象的语言.利用多态性技术,可以调用同一个函数名的函数,实现完全不同的功能. 多态性(polymorphism) ...
- C++中的多态及虚函数大总结
多态是C++中很关键的一部分,在面向对象程序设计中的作用尤为突出,其含义是具有多种形式或形态的情形,简单来说,多态:向不同对象发送同一个消息,不同的对象在接收时会产生不同的行为.即用一个函数名可以调用 ...
- C++多态性与虚函数
派生一个类的原因并非总是为了继承或是添加新的成员,有时是为了重新定义基类的成员,使得基类成员“获得新生”.面向对象的程序设计真正的力量不仅仅是继承,而且还在于允许派生类对象像基类对象一样处理,其核心机 ...
- c++ 虚函数多态、纯虚函数、虚函数表指针、虚基类表指针详解
静态多态.动态多态 静态多态:程序在编译阶段就可以确定调用哪个函数.这种情况叫做静态多态.比如重载,编译器根据传递给函数的参数和函数名决定具体要使用哪一个函数.动态多态:在运行期间才可以确定最终调用的 ...
随机推荐
- App性能提升方法
总体思路:精简请求数 1.css sprit 图像拼合,将所有可拼接的所有图像拼接为一整张图像,然后再利用css中的position定位来处理,降低图片的请求数 2.懒加载:只渲染客户端用户可见区域[ ...
- git 终端常输入命令
cd 输入命令 ls 返回目录 git add . 相当于保存代码 git commit -m "" 相当于提交 get pull把服务器上代码拉回本地代码. get pust 刷 ...
- 将mysql的查询结果输出到文件
在sql命令中我们可以查询到前数行的表,同时也可以将查询结果输出到txt文档 语句:select * from tablename into outfile 'filename.txt'; 例如:se ...
- 《shell下sort排序命令的使用》
首先建立一个文件,很乱,没有规律: 正排序: 倒排序: Uniq 删除文件中的重复行:用此命令要先对文件进行排序. 对文件冗余,只要文件所有重复的字符显示一次: 显示1-7,不重复的行: 只显示1-7 ...
- Android Audio Play Out Channel
1: 7嘴8舌 扬声器, 耳机, 和听筒 就是通过: audiomanager.setmode(AudioManager.MODE_IN_COMMUNICATION)audiomanager.setS ...
- Delphi 中的全局快捷键+给指定窗体发送按键
[背景] 公司做视频影像采集,平时采集图像的时候都需要打开采集窗口,然后需要开着采集窗口来进行图像采集.同事问我能不能做一个全局快捷键,哪怕我没有操作也可以采集图像.说干就干,一直想做全局快捷键了,网 ...
- IIS6下, web.config配置为targetFramework="4.0"时出404错误
打开IIS管理器,在"Web 服务扩展" 中 将ASP.NET v4.0设置为允许就好了.这个选项默认是禁止的.
- Oracle计算两个整数的和与这两个整数的差与商
PL/SQL(Procedural Language/SQL)是一种过程化语言. PL/SQL都是以(BLOCK)块为基本单位,整个PL/SQL块分为三部分 1.声明(Declare) 2.执行(以B ...
- ORA-00845
系统版本: [root@yoon ~]# more /etc/oracle-releaseOracle Linux Server release 5.7 数据库版本: Oracle Database ...
- 简单的C#线程开发实例(隔一秒改变一下Label的Text)
要实现的效果:点击按纽,窗口上的label上出现1~100数字的变化. 第一个实例(把窗口上的label上文字改成0): using System; using System.Windows.Form ...