• 虚拟函数的静态决议 和 RTTI 小例子


    一:先说虚拟函数的静态决议(Static Resolution)

      在两种情况下,虚拟函数机制不会出现预期行为:1、在基类的constructor和destructor内;2、当我们使用的是基类的对象,而非基类对象的pointer 或 reference时

      上述第二种情况很好理解,第二种情况是C++多态机制的重要概念。第一种情况其实也很简单,但我才刚开始学习C++,怕以后自己会不小心把一些虚函数写在constructor 或 destructor里,固写此文章记录一下,下面给出第一种情况的解释:

      -----------------摘抄Essential C++解释开始-----------------

      当我们构造派生类对象时,基类的constructor会先被调用。如果在基类的constructor中调用某个虚拟函数,会发生什么事?调用的应该是派生类所定义的那一份吗?

      问题出在此刻派生类中的data member尚未初始化。如果此时调用派生类的那一份虚拟函数,它便有可能取用未经初始化的data members,这可不是一件好事。

      基于这个理由,在基类的constructor中,派生类的虚拟函数绝对不会被调用。同理,如果在基类的destructor中调用虚拟函数,此规则同样成立。

      -----------------摘抄Essential C++解释结束-----------------

    举例:

      基类代码

      

     1 #pragma once
    2 #include <typeinfo>
    3 #include <iostream>
    4 class num_sequence
    5 {
    6 public:
    7 num_sequence(void);
    8 virtual const char* what_am_i() const;
    9 virtual void display() const { std::cout << "Based decontroctor" << std::endl; }
    10 virtual ~num_sequence(void) { display(); }
    11 };

      派生类代码

      

     1 #pragma once
    2 #include "num_sequence.h"
    3
    4 class Fibonacci :
    5 public num_sequence
    6 {
    7 public:
    8 Fibonacci(void);
    9 virtual void display() const { std::cout << "Drived destructor" << std::endl; }
    10 ~Fibonacci(void) { display(); };
    11 void testTypeId() { std::cout << "testTypeIdFunction" << std::endl; }
    12 };

    然后在main里测试:

      Fibonacci fib;
      num_sequence *ps = &fib;

    输出的结果是:

      Derived destructor
      Based destructor
      请按任意键继续. . .

    即:分别调用子类和基类的析构函数(调用基类的析构函数时,基类析构函数里的display()函数没有动态执行子类的display())

    二:RTTI

      基类num_sequence.cpp中加入

    inline const char* num_sequence::what_am_i() const
    {
    return typeid( *this ).name();
    }

    主main程序里面:

      

     1 Fibonacci fib;
    2 num_sequence *ps = &fib;
    3
    4 if ( typeid(*ps) == typeid(Fibonacci) )
    5 {
    6 ps->Fibonacci::testTypeId(); // 错误
    7 ps->testTypeId();// 错误
    8 if ( Fibonacci *pf = dynamic_cast<Fibonacci*> (ps) )
    9 {
    10 pf->testTypeId();
    11 }
    12 }

      Line6、Line7错误,这里ps并不"知道"它所寻址的对象实际上是什么型别--纵使我们知道,typeid及虚拟函数机制也知道。。

      为了调用Fibonacci所定义的testTypeId(),我们必须指示编译器,将ps的型别转换为Fibonacci指针。

      1、static_cast可以转换:Fibonacci *pf = static_cast<Fibonacci*>( ps );

      但存在危险,因为编译器无法确认我们所进行的转换操作是否完全正确。

      2、dynamic_cast:这是一个RTTI运算法,会进行执行期检验操作,检验ps所指对象是否属于Fibonacci类。如果是,转换操作便会发生,于是pf便指向该Fibonacci对象。如果不是,dynamic_cast运算符返回0。

  • 相关阅读:
    Authorize 示例
    javscript 实现iframe加载内容页出现Loading效果
    泛型的Distinct(IEqualityComparer)的用法
    关于ViewData与TempData
    将表 自增长列 清零 循环插入时间自增长
    linq count() sum() Min() Max() Average() 用法
    分页的存储过程
    将图片文件与文本文件合并成图片文件
    asp.net mvc利用Json验证数据和导向页面,解决重复提交问题
    JQUERY DIV浮动提示信息
  • 原文地址:https://www.cnblogs.com/ziyoudefeng/p/2407907.html
Copyright © 2020-2023  润新知