类型识别(五十四)

我们在面向对象中可能会出现这样的情况:基类指针指向子类对象、基类引用成为子类对象的别名。如下

静态类型便指的是变量(对象)自身的类型,动态类型是指指针(引用)所指向对象的实际类型。基类指针是否可以强制类型转换为子类指针取决于动态类型!下面的这种转换方式是危险的

那么我们在 C++ 中如何得到动态类型呢?解决方案便是利用多态:1、在基类中定义虚函数返回具体的类型信息;2、所有的派生类都必须实现类型相关的虚函数;3、每个类中的类型虚函数都需要不同的实现。

下来我们就用代码来分析

#include <iostream>
#include <string>

using namespace std;

class Base
{
public:
    virtual string type()
    {
        return "Base";
    }
};

class Derived : public Base
{
public:
    string type()
    {
        return "Derived";
    }
    
    void print()
    {
        cout << "I'm Derived." << endl;
    }
};

class Child : public Base
{
public:
    string type()
    {
        return "Child";
    }
};

void test(Base* b)
{
    if( b->type() == "Derived" )
    {
        Derived* d = static_cast<Derived*>(b);
        
        d->print();
    }
    
    cout << dynamic_cast<Derived*>(b) << endl;
}

int main()
{
    Base b;
    Derived d;
    Child c;
    
    test(&b);
    test(&d);
    test(&c);

    return 0;
}

我们利用强制类型转换的时候,首先得考虑指向的对象是不是和需要转换的对象是一致的,如果是则进行转换。否则会翻车。我们看看编译结果

我们看到只输出了 Derived 类。我们之前说过,在进行继承相关的转换时,最好用 dynamic_cast 关键字,下面我们将 test 函数中的注释去掉,再来编译看看

我们看到成功实现转换的打印出了地址,没成功的都为 0 了。我们利用多态成功的实现了动态类型的识别。但是有点小缺陷,就是必须从基类开始通过类型虚函数,所有的派生类都必须重写类型虚函数,每个派生类的类型名必须唯一。

那么在 C++ 中是通过了类型识别关键字的,typeid 关键字用于获取类型信息。typeid 关键字返回对应参数的类型信息,它返回一个 type_info 类对象,当 typeid 的参数为 NULL 时将抛出异常。typeid 的注意事项:当参数为类型时,返回静态类型信息;当参数为变量时,不存在虚函数表则返回静态类型信息,存在虚函数表则返回动态类型信息。

下来还是以代码为例来进行分析

#include <iostream>
#include <string>
#include <typeinfo>

using namespace std;

class Base
{
public:
    virtual ~Base()
    {
    }
};

class Derived : public Base
{
public:
    void print()
    {
        cout << "I'm Derived." << endl;
    }
};

class Child : public Base
{
public:
    string type()
    {
        return "Child";
    }
};

void test(Base* b)
{
    const type_info& tb = typeid(*b);
    
    cout << tb.name() << endl;
}

int main()
{
    int i = 0;
    
    const type_info& tiv = typeid(i);
    const type_info& tvv = typeid(int);
    
    cout << (tiv == tvv) << endl;
    
    cout << endl;
    
    Base b;
    Derived d;
    
    test(&b);
    test(&d);

    return 0;
}

我们打印 i 和 int 的信息应该是一致的,所以应该打印出 1。来看看编译结果

我们来看看如果不定义虚函数呢,看看编译结果

我们看到如果定义了虚函数的话,打印的便是动态类型的;没定义的话,打印的便是静态类型的。下来我们再用 BCC 编译器来看看结果

我们看到 typeid 关键字在不同的编译器上打印的行为是有点区别的。通过对类型识别的学习,总结如下:1、C++ 中有静态类型和动态类型的概念;2、利用多态能够实现对象的动态类型识别;3、typeid 是专用于类型识别的关键字,它能够返回对象的动态类类型信息。

欢迎大家一起来学习 C++ 语言,可以加我QQ:243343083。

原文地址:http://blog.51cto.com/12810168/2124857

时间: 2024-10-02 00:27:39

类型识别(五十四)的相关文章

QT开发(五十四)———QML组件

QT开发(五十四)---QML组件 QML组件是由基本元素组合成的一个复杂的可重用的组合元素.QML 提供了多种方法来创建组件. 基于文件的组件将QML元素放置在一个单独的文件中,然后给文件一个名字,可以通过名字来使用组件.如果有一个文件名为Cell.qml,就可以在QML中使用Cell { - }形式.自定义组件的文件名的首字母必须大写. Cell.qml文件: import QtQuick 2.0   Item {     id: container     property alias c

第三百五十四节,Python分布式爬虫打造搜索引擎Scrapy精讲—数据收集(Stats Collection)

第三百五十四节,Python分布式爬虫打造搜索引擎Scrapy精讲-数据收集(Stats Collection) Scrapy提供了方便的收集数据的机制.数据以key/value方式存储,值大多是计数值. 该机制叫做数据收集器(Stats Collector),可以通过 Crawler API 的属性 stats 来使用无论数据收集(stats collection)开启或者关闭,数据收集器永远都是可用的. 因此您可以import进自己的模块并使用其API(增加值或者设置新的状态键(stat k

“全栈2019”Java第五十四章:多态详解

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第五十四章:多态详解 下一章 "全栈2019"Java第五十五章:方法的静态绑定与动态绑定 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Java学习小组"

学习五十四

十四周四次课(5月14日)16.1 Tomcat介绍16.2 安装jdk16.3 安装Tomcat 扩展java容器比较 http://my.oschina.net/diedai/blog/271367 http://www.360doc.com/content/11/0618/21/16915_127901371.shtmlj2ee.j2se.ejb.javabean.serverlet.jsp之间关系 http://bbs.csdn.net/topics/50015576tomcat ser

C#高级编程五十四天----Lookup类和有序字典

Lookup类 Dictionary<Tkey,TValue>只为每个键支持一个值.新类Lookup<Tkey,TValue>是.NET3.5中新增的,它类似与Dictionary<Tkey,TElement>,但把键映射带一个值集上.这个类在程序及System.Core中实现,用System,Linq命名空间定义. Lookup<Tkey,TElement>的方法和属性如下表: 属性名或者方法名 说明 Count 属性Count返回集合中的元素个数 Ite

猫猫学iOS(五十四)多线程网络之NSOperation重要知识

猫猫分享,必须精品 原创文章,欢迎转载.转载请注明:翟乃玉的博客 地址:http://blog.csdn.net/u013357243?viewmode=contents 一:队列的类型与队列添加任务 1: 主队列 [NSOperationQueue mainQueue] 添加到"主队列"中的操作,都会放到主线程中执行. 2:非主队列 [[NSOperationQueue alloc] init] 添加到"非主队列"中的操作,都会放到子线程中执行. 3:队列添加任务

C#编程(五十四)----------Lookup类和有序字典

原文链接: http://blog.csdn.net/shanyongxu/article/details/47071607 Lookup类 Dictionary<Tkey,TValue>只为每个键支持一个值.新类Lookup<Tkey,TValue>是.NET3.5中新增的,它类似与Dictionary<Tkey,TElement>,但把键映射带一个值集上.这个类在程序及System.Core中实现,用System,Linq命名空间定义. Lookup<Tkey

JAVA学习第五十四课 — IO流(八)打印流 &amp; 序列流

一.综合练习-文件清单列表 获取指定目录下,指定扩展名的文件(含子目录),并将这些文件的绝对路径写到一个文本文件中.也就是建立一个指定扩展名的文件列表 1.深度遍历 2.过滤器->容器 3.写入文件 import java.util.List; import java.io.*; import java.util.ArrayList; public class Main { public static void main(String[] args) throws IOException { F

一起talk C栗子吧(第一百五十四回:C语言实例--socket通信地址系统调用二)

各位看官们,大家好,上一回中咱们说的是socket通信地址系统调用的例子,这一回咱们继续说该例子.闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,我们在上一回介绍的通信地址系统调用有效地解决了数据存储方式的问题,不过,还有一个系统调用也可以解决这种问题,这一回我们将介绍该系统调用:getaddrinfo. 函数原型 该系统调用从其名字上看是用来获取地址的信息,这里的地址主要指套接字通信地址.它获取到的地址信息不需要进行字节序转换,我们可以直接用来进行套接字通信.不过,我们不能只看名字