1,为什么会提出类型识别概念呢?

1,为什么在 C 语言中没有提出这个概念呢,就是因为在 C++ 中引入了面向对象的特性,面向对象里面有一个非常重要的原则就是赋值兼容性原则;

2,在面向对象中可能出现下面的情况:

1,基类指针指向子类对象;

2,基类引用成为子类对象的别名;

3,示意图:

1,p 指针字面意思是用来指向父类对象,而 p 又指向了子类对象;

2,当得到 p 指针后,我们是否有能力判断当前指针指向的是父类对象还是子类对象吗?目前没有办法通过一个父类指针来判断它指向的究竟是父类对象还是一个子类对象;

3,上图中展示的指针 p “静态类型”是 Base*,“静态类型”是指针它期望的类型,赋值兼容性使得 p 有可能指向的不是它期望的类型,而是子类类型,这时指针所指向的类型就叫做“动态类型”;

4,引用 r 静态类型是 Base&,r 的本意是引用父类的别名,但由于赋值兼容性,它也可以引用子类的别名,无法确定它的别名究竟是父类别名还是子类别名;

3,类型识别:

  1,静态类型:

  1,变量(对象)自身的类型;

  1,写代码时就可以完全确定;

 2,动态类型:

  1,指针(引用)所指向对象的实际类型;

  1,写代码时确定不了;

    1,b 在代码运行时不一定指向父类对象,它有可能指向一个子类对象,因此 b 指针指向的是动态类型;

     2,当 b 指针指向的是子类对象,则程序正常运行,将父类类型转换为子类类型是非常危险的,有可能产生 Bug;

(3),基类指针是否可以强制类型转换为子类指针取决于动态类型;

 1,这样的转换和静态类型转换没有丝毫关系;

3,C++ 中如何得到动态类型?

4,动态类型识别:

1,解决方案(老师的思路):利用多态

1,在基类中定义虚函数返回具体的类型信息;

2,所有的派生类都必须实现类型相关的虚函数;

3,每个类中的类型虚函数都需要不同的实现;

1,调用类型虚函数就可以知道当前的对象究竟是什么类型,这样就可 以得到动态类型,达到动态类型识别效果;

5,动态类型识别编程实验:

 #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 printf()
{
cout << "I'm a Derived." << endl;
}
}; class Child : public Base
{
public:
string type()
{
return "Child";
}
}; void test(Base* b)
{
/* 危险的转换方式 */
// Derived* d = static_cast<Derived*>(b); if( b->type() == "Derived" )
{
Derived* d = static_cast<Derived*>(b); // 转换 d->printf(); // 使用指针 d,这里只是说明问题;
} // cout << dynamic_cast<Derived*>(b) << endl; // 不够用,舍弃;
} int main(int argc, char *argv[])
{
Base b;
Derived d;
Child c; test(&b); // 用 dynamic_cast 时,父类转换子类不成功,返回 0;
test(&d);
test(&c); // 用 dynamic_cast 时,子类间转换不成功,返回 0; return ;
}

1,最正规的转换用法应该是 dynamic_cast,可以判断 dynamic_cast 返回值来判断指针转换是否成功;

2,这里我们需要知道动态的类型究竟是什么,所以 dynamic_cast 在这里根本不够用,仅仅只能告诉我们转换是否成功;

3,这里通过虚函数返回类型名的方式就可以成功的得到动态类型名;

4,但是这里有个问题是长期维护,只要我们写一个新的类出来,必须都要实现这个虚函数,如果没有实现这个虚函数,后果将会造成对象的动态类型和实     际不符合的错误,并且造成 if() 语句中的调用不会成功;

6,多态解决方案的缺陷:

1,必须从基类开始提供类型虚函数;

2,所有的派生类都必须重写类型虚函数;

1,长期维护并不好;

3,每个派生类的类型名必须唯一;

7,C++ 提供了 typeid 关键字用于获取类型信息:

1,typeid 关键字返回对应参数的类型信息;

1,类的和基础类型的类型信息;

2,typeid 返回一个 type_info 类对象;

3,当 typeid 的参数为 NULL 时将抛出异常;

1,参数可以是类型名、变量名;

8,typeid 关键字的使用:

1,代码示例:

 int i = ;

 const type_info& tiv = typeid(i);  // 将 i 的类型信息放到 type_info 中去;
const type_info& tii = typeid(int); cout << (tiv == tii) << endl;

9,typeid 的注意事项:

1,当参数为类型时,返回静态类型信息;

2,当参数为变量时:

1,参数变量内部不存在虚函数表时,返回静态类型信息;

2,参数变量内部存在虚函数表时,返回动态类型信息;

10,tpeid 类型识别编程实验:

 #include <iostream>
#include <string>
#include <typeinfo> // typeid 返回的对象类型 tyep_info 所对应的头文件; using namespace std; class Base
{
public:
virtual ~Base()
{
}
}; class Derived : public Base
{
public:
void printf()
{
cout << "I'm a Derived." << endl;
}
}; void test(Base* b)
{
const type_info& tb = typeid(*b); cout << tb.name() << endl;
} int main(int argc, char *argv[])
{
int i = ; const type_info& tiv = typeid(i);
const type_info& tii = typeid(int); cout << (tiv == tii) << endl; // 1; Base b;
Derived d; /* 通过不同的对象调用得到类型信息相同,因为 b 对象没有虚函数表,此时返回静态类型信息 */
test(&b); // 4Base;
test(&d); // 4Base; /* 对象 b 里加上虚函数表后,返回动态类型信息 */
test(&b); // 4Base;(在 Linux 的 g++ 编译器下面显示的)Base;
         //(在 windows 的 BCC 编译器下面显示的)
test(&d); // 7Derived;(在 Linux 的 g++ 编译器下面显示的)
         // Derived;(在 windows 的 BCC 编译器下面显示的) return ;
}

1,typeid 在不同的编译器内部实现是不同的;

11,小结:

1,C++ 中有静态类型和动态类型的概念;

2,利用多态能够实现对象的动态类型识别;

1,维护成本高,一旦不小心出错,整个项目就会有 bug;

3,typeid 是专用于类型识别的关键字;

4,typeid 能够返回对象的动态类型信息;

1,使用 typeid 的时候,一定不要进行某些类型上面的假设,因为不同的编译器处理类型的名字它的方式是不一样的;

C++中的类型识别的更多相关文章

  1. 第66课 C++中的类型识别

    1. 类型识别 (1)在面向对象中可能出现下面的情况 ①基类指针指向子类对象 ②基类引用成为子类对象的别名 ▲静态类型——变量(对象)自身的类型(定义变量类型时类型或参数类型) ▲动态类型——指针(引 ...

  2. JS中的类型识别

    JS为弱类型语言,所以类型识别对JS而言尤为重要,JS中常用的类型识别方法有4种:typeof.Object.prototype.toString.constructor和instanceof. (1 ...

  3. 框架原理第二讲,RTTI,运行时类型识别.(以MFC框架讲解)

    框架原理第二讲,RTTI,运行时类型识别.(以MFC框架讲解) 一丶什么是RTTI,以及RTTI怎么设计 通过第一讲,我们知道了怎么样升成一个窗口了,以及简单的消息循环. 第二讲则是主要讲解RTTI ...

  4. 关于js中的类型内容总结(类型识别)

    JS 有7种数据类型: 6种原始类型:Boollean    String   Number    Null    Underfined   Symbol 引用类型:Object 类型识别主要有以下四 ...

  5. RTTI 运行时类型识别 及异常处理

    RTTI   运行时类型识别 typeid  ------  dynamic_cast dynamic_cast 注意事项: 1.只能应用于指针和引用之间的转化 2.要转换的类型中必须包含虚函数 3. ...

  6. RTTI (Run-Time Type Identification,通过运行时类型识别) 转

    参考一: RTTI(Run-Time Type Identification,通过运行时类型识别)程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型.   RTTI提供了以下两个 ...

  7. 数据库中字段类型对应的C#中的数据类型

    数据库中字段类型对应C#中的数据类型: 数据库                 C#程序 int int32 text string bigint int64 binary System.Byte[] ...

  8. MFC六大核心机制之二:运行时类型识别(RTTI)

    上一节讲的是MFC六大核心机制之一:MFC程序的初始化,本节继续讲解MFC六大核心机制之二:运行时类型识别(RTTI). typeid运算子 运行时类型识别(RTTI)即是程序执行过程中知道某个对象属 ...

  9. 拼接json时小心C#中bool类型转化

    C#中bool类型的值,在ToString时会有如下转化:true—>Ture ; false—>False这是拼接到json串中就会出现如下结果:{ "no": &q ...

随机推荐

  1. Spring实例化相关问题

    1.当Controller或者Service使用new来实例化时,能不能正常调用使用Resource声明的变量 不能,使用new来实例化时,所有使用Resource声明的变量均为null

  2. #5 DIV2 A POJ 3321 Apple Tree 摘苹果 构建线段树

    Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 25232   Accepted: 7503 Descr ...

  3. 暑假集训 #3div2 C Sequence 数字找规律

    C. Sequence (64 Mb, 1 sec / test)Integer sequences are very interesting mathematical objects. Let us ...

  4. [CF1223G/1240E]Wooden Raft 题解

    前言 上午一场模拟赛(发布前很久,因为这题题解太长了),发现T3特别珂怕,打开题解,发现一行字: 不要再问了,再问就是CF 1240E 当场去世.jpg. 在下文中,我们记 \(A\) 为 \(a\) ...

  5. [HG]Market 题解

    题目描述 在比特镇一共有 \(n\) 家商店,编号依次为 \(1\) 到 \(n\). 每家商店只会卖一种物品,其中第 \(i\) 家商店的物品单价为 \(c_i\),价值为 \(v_i\),且该商店 ...

  6. Codeforces 1213G Path Queries

    cf题面 中文题面 给一棵无根树,每条边有边权.然后q个询问,每次询问给个w,求树上有多少对点之间的路径上的最大值小于等于w. 解题思路 离线.先把所有边按照边长升序排序,再把所有询问按照w升序排序. ...

  7. JS框架_(JQuery.js)点赞按钮动画

    百度云盘 传送门 密码: 0ihy 点赞按钮动画效果: (点击一次随机生成一颗小爱心,作为点赞动画~) <!doctype html> <html lang="en&quo ...

  8. python3 类的属性、方法、封装、继承及小实例

    Python 类 Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法. 对象可以包含任意数量和类型的数据. p ...

  9. python学习之路(3)

    字符串和编码 因为python最早只支持ASCII编码普通的字符串'ABC'在Python内部都是ASCII编码的.Python提供了ord()和chr()函数,可以把字母和对应的数字相互转换 后来p ...

  10. hdu 4763 看毛片(单纯next数组的应用--纯正O(n))

    因为需要负责队内的字符串题,开始刷,做到这道,开始想不出来,上网找题解, 然后就惊了,为什么你们这么暴力都可以过的啊,1e6啊,后来又想了下会做了 贴下代码 #include <iostream ...