[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++ 虚函数多态、纯虚函数、虚函数表指针、虚基类表指针详解
静态多态.动态多态 静态多态:程序在编译阶段就可以确定调用哪个函数.这种情况叫做静态多态.比如重载,编译器根据传递给函数的参数和函数名决定具体要使用哪一个函数.动态多态:在运行期间才可以确定最终调用的 ...
随机推荐
- 采用Service实现本地推送通知
在android的应用层中,涉及到很多应用框架,例如:Service框架,Activity管理机制,Broadcast机制,对话框框架,标题栏框架,状态栏框架,通知机制,ActionBar框架等等. ...
- 设置datagridview中button按钮的背景颜色
问题:DataGridViewButtonColumn()在datagridview中创建按钮列,如何设置按钮的背景颜色(不是单元格的背景颜色). 回答:可以在dataGridView1_CellPa ...
- Android开发之计算器(一)界面设计之activity_main布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...
- 社区发现算法问题&&NetworkX&&Gephi
在做东西的时候用到了社区发现,因此了解了一下有关社区发现的一些问题 1,社区发现算法 (1)SCAN:一种基于密度的社团发现算法 Paper: <SCAN: A Structural Clust ...
- 【面试虐菜】—— JAVA面试题(3)
1 throws与throw的区别 解析:throws和throw是异常处理时两个常见的关键字,初级程序员常常容易正确理解throw和throws的作用和区别,说明已经能比较深入理解异常处理.Thro ...
- mysql-5.5.46源码编译安装
1.安装准备 cat /etc/redhat-release uname -r yum install ncurses-devel cmake automake autoconf make gcc g ...
- [转]Linux中find常见用法示例
Linux中find常见用法示例[转]·find path -option [ -print ] [ -exec -ok command ] {} \;find命令的参 ...
- .NET书籍推荐
任何语言的学习,要快速掌握,不在看书,而在实践.——题记 .NET技术从1.1发展到2.0,内核基本完善,从.NET 2.0开始学习是个明智的选择.而NET 3.5以及即将推出的.NET 4.0所新加 ...
- oracle-12c-rac 报:ORA-01078
OS: Oracle Linux Server release 5.7 DB: Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - ...
- Sales_item
#ifndef SALESITEM_H #define SALESITEM_H // Definition of Sales_item class and related functions goes ...