目录

    • 静态类型 vs 动态类型、静态绑定 vs 动态绑定
    • 虚函数动态绑定实现机制、虚析构函数
    • 多态性

一.静态 vs 动态

  静态类型 VS 动态类型。静态类型指的是对象声明的类型,在编译器确定的。动态类型指的是对象的所指向的类型,动态类型是可以更改的,静态类型无法更改。继承关系会导致对象的指针和引用具有静态类型和动态类型,因为继承关系的存在中可能会存在类型之间的向上向下类型转换。静态绑定 VS 动态绑定。某特性(函数)依赖与对象的静态类型,在编译期确定,某特性(函数)依赖于对象的动态类型,在运行期确定。只有通过基类的引用或者指针调用虚函数时,才能发生动态绑定,如果使用对象来操作虚函数的话,仍然会采用静态绑定的方式。因为引用或者指针既可以指向基类对象,也可以指向派生类对象的基类部分,用引用或者指针调用的虚函数。例如下面的例子中,pd的静态类型是D*,pb的静态类型是B*,是在编译器确定的;pd和pb的动态类型都是D*。DoSomething()普通的成员函数是在编译器静态绑定的,调用各自的静态类型中的方法。vfun()是虚成员函数,虚函数是动态绑定的,因此调用动态类型的方法,也就是D类型中vfun。

 #include <iostream>
using namespace std; class B
{
public:
void DoSomething(){
std::cout << "B::DoSomething()" << endl;
}
virtual void vfun(){
std::cout << "B::vfun()" << endl;
}
}; class D : public B
{
public:
void DoSomething(){
std::cout << "D::DoSomething()" << endl;
}
virtual void vfun(){
std::cout << "D::vfun()" << endl; }
}; int main()
{
D* pd = new D(); //指针存在注意静态类型和动态类型
B* pb = pd; //指正注意静态类型和动态类型
pd->DoSomething(); //普通成员函数,静态绑定静态类型中的方法
pb->DoSomething(); //普通成员函数,静态绑定静态类型中的方法 pd->vfun(); //虚成员函数,动态绑定到动态类型中的方法
pb->vfun();       //虚成员函数,动态绑定到动态类型中的方法
return ;
}

二.虚函数动态绑定的实现机制

  对象的指针或者引用调用虚函数的行为是动态绑定。虚函数是通过虚函数表来实现的。对于每一个含有虚函数的类,编译器会为其创建一个虚函数表Vtable,虚函数表中记录JMP指令的地址。类的虚函数表被该类的所有对象共享,编译器会为每个虚函数的实例分配指向该类的虚函数表的指针。当一个含有虚成员函数的类被继承后,器派生类中的同名函数会自动的成为虚函数,因此子类在重写这个虚函数时,可以添加,也可以不加virtual关键字,习惯上会加上virtual使得程序更加的清晰。父类指针调用虚成员函数是多态在代码层面的体现,这在运行过程中,父类指针将动态绑定(关联)到具体的某个虚函数。指的是在运行期根据父类指针的动态类型的虚函数表来绑定到具体的函数。含有虚函数的类记住使用虚析构函数,否则容易导致派生类的资源无法正常释放。例如下面情况。如果想进一步了解虚函数表需要了解,C++的对象模型,建议查看《C++中对象模型》。

 #include <iostream>
using namespace std; class B
{
public:
void DoSomething(){
std::cout << "B::DoSomething()" << endl;
}
virtual void vfun(){
std::cout << "B::vfun()" << endl;
} ~B(){
std::cout << "~B()" << std::endl;
}
}; class D : public B
{
public:
void DoSomething(){
std::cout << "D::DoSomething()" << endl;
}
virtual void vfun(){
std::cout << "D::vfun()" << endl; }
~D(){
std::cout << "~D()" << std::endl;
}
}; int main()
{
B* pb = new D();
pb->vfun();
delete pb; // ~B();
return ;
}

三 C++多态性体现

  C++多态性代码层面体现的是父类的指针或引用调用虚成员函数。多态产生有三个条件:产生的条件是继承关系、基类中含有虚成员函数、派生类重写基类的虚成员函数。当用父类指针或引用调用虚成员函数,这个调用关系在运行器可能绑定(关联)到不同的子类,产生不同的行为。

 #include <iostream>
using namespace std;
class Person
{
public:
virtual void print(){
std::cout << "I'm a person" << endl;
}
virtual void foo(){}
}; class Chinese : public Person
{
public:
virtual void print(){
std::cout << "I'm as Chinese" << endl;
}
virtual void foo2(){}
};
class American : public Person
{
public:
virtual void print(){
std::cout << "I'm as American" << endl;
}
};
//reference
void printPerson(Person& person){
person.print();
}
//pointer
void printPerson(Person* p){
p->print();
}
int main()
{
Person p;
Chinese c;
American a;
printPerson(&p);
printPerson(&c);
printPerson(&a);
return ;

C++中虚函数的动态绑定和多态性的更多相关文章

  1. C++入门经典-例8.7-多态,利用虚函数实现动态绑定

    1:多态性是面向对象程序设计的一个重要特征,利用多态性可以设计和实现一个易于扩展的系统.在C++语言中,多态是指具有不同功能的函数可以用同一个函数名,这样就可以用一个函数名调用不同内容的函数,发出同样 ...

  2. C++中虚函数的作用浅析

    虚函数联系到多态,多态联系到继承.所以本文中都是在继承层次上做文章.没了继承,什么都没得谈. 下面是对C++的虚函数这玩意儿的理解. 一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你 ...

  3. C++中虚函数的作用是什么?它应该怎么用呢?(转)

    虚函数联系到多态,多态联系到继承.所以本文中都是在继承层次上做文章.没了继承,什么都没得谈. 下面是对C++的虚函数这玩意儿的理解. 一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你 ...

  4. c++中虚函数

    虽然很难找到一本不讨论多态性的C++书籍或杂志,但是,大多数这类讨论使多态性和C++虚函数的使用看起来很难.我打算在这篇文章中通过从几个方面和结合一些例子使读者理解在C++中的虚函数实现技术.说明一点 ...

  5. C++中虚函数的作用和虚函数的工作原理

    1 C++中虚函数的作用和多态 虚函数: 实现类的多态性 关键字:虚函数:虚函数的作用:多态性:多态公有继承:动态联编 C++中的虚函数的作用主要是实现了多态的机制.基类定义虚函数,子类可以重写该函数 ...

  6. 关于C++与Java中虚函数问题的读书笔记

    之前一直用C++编程,对虚函数还是一些较为肤浅的理解.可近期由于某些原因搞了下Java,发现有些知识点不熟,于是站在先驱巨人的肩上谈谈C++与Java中虚函数问题. Java中的虚函数 以下是段别人的 ...

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

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

  8. c++中虚函数和多态性

    1.直接看下列代码: #include <iostream> using namespace std; class base{ public: void who(){ cout<&l ...

  9. C++中虚函数的作用

    一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你就应该从这里开始) 简单地说,那些被virtual关键字修饰的成员函数,就是虚函数.虚函数的作用,用专业术语来解释就是实现多态性(Po ...

随机推荐

  1. line tension

    <!DOCTYPE html> <html> <head> <title>tension</title> <script type=& ...

  2. hibernate 一对多,由谁维护性能最优

    举例如下 Customer类: public class Customer { private int id; private String name; private Set orders = ne ...

  3. js常用的原生方法

    JavaScript pow() 方法 pow() 方法可返回 x 的 y 次幂的值 语法 Math.pow(x,y) 参数 描述 x 必需.底数.必须是数字. y 必需.幂数.必须是数字. 返回值 ...

  4. 【WP8.1】页面的导航效果

    <Page.Transitions> <TransitionCollection> <NavigationThemeTransition> <CommonNa ...

  5. WinRT 中检查 WiFi 是否可用

    public static bool IsWifiConnected() { bool isWifiConnected = false; ConnectionProfile currentConnec ...

  6. 敏捷项目管理架构(APMF)

    研读许秀影博士的<敏捷项目管理:基础知识与应用实务>一书,其中提到传统项目管理与敏捷项目管理的混合管理模式—敏捷项目管理架构(Agile Project Management Framew ...

  7. clob 转 String

    import javax.sql.rowset.serial.SerialClob; import java.io.BufferedReader; import java.io.IOException ...

  8. C# 创建、部署和调用WebService简单示例

    webservice 可以用于分布式应用程序之间的交互,和不同程序之间的交互. 概念性的东西就不说太多,下面开始创建一个简单的webservice的例子.这里我用的是Visual Studio 201 ...

  9. openstack 创建虚拟机的时候报错: Failed to allocate the network(s), not rescheduling.].

    错误: 实例 "test-gtj" 执行所请求操作失败,实例处于错误状态.: 请稍后再试 [错误: Build of instance 5ea8c935-ee07-4788-823 ...

  10. Android四种数据存储方式

    一.SharedPreference数据存储篇 1.作用范围 (1).它是一种轻型的数据存储方式 (2).本质是基于XML文件存储key-value键值对数据 (3).通常用来存储一些简单的配置方式 ...