首先来看一下派生类和基类成员同名事的处理规则:

  1. 派生类内定义了一个与基类同名的成员,该现象称为同名覆盖,此时,无论派生类内部成员函数还是派生类的对象访问同名成员,如果未加任何特殊标识,则访问派生类中重新定义的同名成员。
  2. 如果派生类内部成员或派生类的对象需要访问基类继承来的同名函数,则必须在同名函数前加上"基类名::"进行类名限定。
  3. 如果基类内部成员函数或基类对象访问同名成员,访问的一定是基类的同名成员。
  4. 用基类的指针,无论是否指向基类对象,都只能访问基类的同名成员。
  5. 用基类的引用,无论是否是基类对象的别名,都只能访问基类的同名成员。

从4、5两条规则可以看到,无论基类指针指向基类对象还是派生类对象,无论引用是基类对象还是派生类对象的别名,始终调用基类成员。那么,怎样才能使基类指针指向基类对象时调用基类同名成员,指向派生类对象时调用派生类同名成员呢?这就是动态联编所能达到的效果。

为了实现动态联编,首先要将同名函数声明为虚函数

虚函数可以通过基类指针或引用访问基类和派生类中被声明为虚函数的同名函数。存在继承关系是首要条件,而且派生类一定是以公有方式继承了基类。同名虚函数在基类和派生类中其函数原型必须完全一致,否则无法通过虚函数实现动态多态性。

第一:为什么派生类必须以公有方式继承基类呢?这是赋值兼容规则的使用前提,以下规则反向均不成立。

  1. 基类对象=公有派生类对象。赋值后的基类对象只能获得基类成员部分,而在派生类中新增加的成员不能被基类对象访问。
  2. 指向基类对象的指针=公有派生类对象的地址。利用赋值后的指针可以间接访问基类的成员,若要间接访问派生类成员,必须强制转换为派生类类型指针访问。
  3. 指向基类对象的指针=指向公有派生类对象的指针。
  4. 基类的引用=公有派生类对象,即派生类对象可以初始化基类的引用。赋值后的引用只可以访问基类成员,无法访问派生类新增成员,因为无法对引用进行强制类型转换。

一般来说,可以将类层次中具有共性的成员函数声明为虚函数,而个性的函数没有必要声明为虚函数。但以下情况是特例:

  1. 静态成员函数不能声明为虚函数。因为静态成员函数不属于某一个对象,没有多态性。
  2. 内联函数不恩能够声明为虚函数。因为内联函数的执行代码是明确的,没有多态性的特征。
  3. 构造函数不能是虚函数。因为构造函数声明为虚函数是完全没有意义的。
  4. 析构函数往往被声明为虚函数。

如果基类的析构函数声明为虚函数,则该类所有派生类的析构函数也自动成为虚函数而无需显式声明。在这种情况下,由于实施多态性是将基类的指针指向派生类的对象,若果删除该指针,则会调用该指针指向的派生类的析构函数,而派生类的析构函数又自动调用基类的析构函数,这样整个派生类的对象被完全释放。如果析构函数不是虚函数,则编译器实施静态绑定,在删除基类指针时,只调用指针所属基类的析构函数而不调用派生类的析构函数,这会导致析构不完全。所以当派生类中存在指针数据成员,又通过该指针进行了动态空间申请时,将析构函数声明为虚函数是非常有必要的。

第二:为什么同名虚函数在基类和派生类中其函数原型必须完全一致?一个函数在基类和公有派生类中拥有相同的函数名,但函数返回值类型不同,或者是形式参数表不同,即使在基类中被声明为虚函数,也不具备多态性。这种情况下,基类中的函数无虚函数特性,当做普通函数使用,而在派生类中存在同名函数就是本文开始讲到的同名覆盖现象,无法通过基类的指针或引用实现动态多态性。

下面的几条面试题可以巩固本文的知识。

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++]虚函数-同名访问的更多相关文章

  1. C++之虚函数和多态

    干货较多-需要自己深思理解: C++支持两种多态性: 1.编译时多态性(静态绑定-早绑定) 在程序编译阶段即可以确定下来的多态性 通过使用 重载机制(重载函数)实现 (模板)http://blog.c ...

  2. C++中虚函数功能的实现机制

    要理解C++中虚函数是如何工作的,需要回答四个问题. 1.  什么是虚函数. 虚函数由于必须是在类中声明的函数,因此又称为虚方法.所有以virtual修饰符开始的成员函数都成为虚方法.此时注意是vir ...

  3. c++ 一般虚函数

    类图: 代码: #include <iostream> using namespace std; class CFather //父类 { public: virtual void dis ...

  4. virtual之虚函数,虚继承

    当类中包含虚函数时,则该类每个对象中在内存分配中除去数据外还包含了一个虚函数表指针(vfptr),指向虚函数表(vftable),虚函数表中存放了该类包含的虚函数的地址. 当子类通过虚继承的方式从父类 ...

  5. 【C++】虚函数的实现机制

    一.什么是虚函数? 虚函数是在类中由virtual关键字声明的成员函数,并且每一个含有虚函数的类都至少有一个与之对应的虚函数表,其中存放着该类所有虚函数对应的函数指针 在基类中进行如下定义: virt ...

  6. C++——多态性 与 虚函数

    多态性 多态性是面向对象程序设计的关键技术之一.若程序设计语言不支持多态性,不能称为面向对象的语言.利用多态性技术,可以调用同一个函数名的函数,实现完全不同的功能. 多态性(polymorphism) ...

  7. C++中的多态及虚函数大总结

    多态是C++中很关键的一部分,在面向对象程序设计中的作用尤为突出,其含义是具有多种形式或形态的情形,简单来说,多态:向不同对象发送同一个消息,不同的对象在接收时会产生不同的行为.即用一个函数名可以调用 ...

  8. C++多态性与虚函数

    派生一个类的原因并非总是为了继承或是添加新的成员,有时是为了重新定义基类的成员,使得基类成员“获得新生”.面向对象的程序设计真正的力量不仅仅是继承,而且还在于允许派生类对象像基类对象一样处理,其核心机 ...

  9. c++ 虚函数多态、纯虚函数、虚函数表指针、虚基类表指针详解

    静态多态.动态多态 静态多态:程序在编译阶段就可以确定调用哪个函数.这种情况叫做静态多态.比如重载,编译器根据传递给函数的参数和函数名决定具体要使用哪一个函数.动态多态:在运行期间才可以确定最终调用的 ...

随机推荐

  1. 求单链表倒数第m个结点

    问题:求单链表倒数第m个结点,要求不准求链表的长度,也不许对链表进行逆转 解:设置两个指针p和q,p.q指向第一个结点.让p先移动到链表的第m个结点,然后p和q同时向后移动,直到p首先到达尾结点.此时 ...

  2. 安装apk文件报waiting for device 时解决办法

    C:\Users\root>adb install d:\rry_0514.apkerror: more than one device and emulator- waiting for de ...

  3. 正则匹配 去掉 多余的js和html标签

    $reg17 = '/><strong>公司介绍<\/strong><\/td>([\S\s*]+?)<\/div>/'; $this->d ...

  4. Android String format 通过value 下的string.xml 文件

    <string name="format_coordinate" formatted="false">%s %d° %d\' %d\" % ...

  5. JavaScript 同源策略

    在JavaScript安全性限制Same-Origin Policy(同源策略)=>JavaScript只能访问与包含它的文档在同一域下的内容. 同源=>域名+协议+端口相同.

  6. 【zendstudio】如何利用zendstudio新建 或导入php项目

    一.利用ZendStudio创建 PHP Project 1. 打开ZendStudio, 选择:File à New à PHP Project, 如下图所示: 于是弹出如下界面: 在”Projec ...

  7. Windows下关于Composer使用时出现的问题及解决办法

    问题一: Fatal error: Call to undefined method Composer\Package\CompletePackage::getTrans portOptions() ...

  8. Oracle RAC Failover

    Oracle  RAC 同时具备HA(High Availiablity) 和LB(LoadBalance). 而其高可用性的基础就是Failover(故障转移). 它指集群中任何一个节点的故障都不会 ...

  9. JAVA的字节码技术

    1.什么是字节码? 字节码 byteCode JVM能够解释执行的.java程序的归宿,但是从规范上来讲和Java已没有任何关系了.一些动态语言也可以编译成字节码在JVM上运行.字节码就相当于JVM上 ...

  10. 【jquery】 API讲解 内部培训资料

    资料在百度云盘 一.jquery  API讲解 1.jquery  api如何使用 jquery  api http://www.hemin.cn/jq/ 2.常用api讲解 选择器: 通过$()获取 ...