📄 rtti.html
字号:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<link rel="stylesheet" href="css/stdlayout.css" type="text/css">
<link rel="stylesheet" href="css/print.css" type="text/css">
<meta content="text/html; charset=gb2312" http-equiv="content-type">
<title>执行时期型态资讯(RTTI)</title>
</head>
<body>
<h3><a href="http://caterpillar.onlyfun.net/GossipCN/index.html">From
Gossip@caterpillar</a></h3>
<h1><a href="CppGossip.html">C++
Gossip: 执行时期型态资讯(RTTI)</a></h1>
在C++这种可以进行多型机制的语言中,您可以将基底类别指标指向衍生类别物件,这种指定通常在执行时期后发生,您并无法在编译时期即得知指标所指向的物件型态,而必须在执行时期取得物件的执行时期资讯。<br>
<br>
RTTI 全名为Run-Time Type Information,也有人作Run-Time Type
Identification,C++中用来取得指标或参考所实际代表的物件,您可以使用typeid()来取得物件于执行时期的资讯,要使用
typeid(),您必须包括<typeinfo>标头档,typeid()使用时传入一个物件: <br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">typeid(object);</span><br>
</div>
<br>
typeid()会传回一个type_info物件,其拥有几个成员可以描述或进行物件的比较:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">const char *name(); // 取得物件型态名称 </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">bool before(const type_info &ob); // 当物件的名称顺序位于ob之前时,传回true </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">bool operator==(const type_info &ob); // 比较物件型态是否相同 </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">bool operator!=(const type_info &ob); // 比较物件型态是否不同</span><br>
</div>
<br>
==与!=运算子在这边被重载为可以比较两个物件的型态是否相同;typeid()也可以使用型态名称作为引数,这通常是用来取得一个type-info物件,并与一个物件作比较时使用:
<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">typeid(type-name);</span><br>
</div>
<br>
用范例来说明typeid()与其成员的使用方法与应用,下面这个程式只是使用name()取得物件的型态名称: <br>
<br>
<pre>#include <iostream> <br>#include <typeinfo> <br>using namespace std; <br><br>class Base { <br>public: <br> virtual void foo() { <br> cout << "Base" << endl; <br> } <br>}; <br><br>class Derived1 : public Base { <br>public: <br> void foo() { <br> cout << "Derived1" << endl; <br> } <br>}; <br><br>class Derived2 : public Base { <br>public: <br> void foo() { <br> cout << "Derived2" << endl; <br> } <br>}; <br><br>int main() { <br> Base *ptr; // 基底类别指标 <br> Base base; <br> Derived1 derived1;<br> Derived2 derived2; <br><br> ptr = &base;<br> cout << "ptr 指向 " <br> << typeid(*ptr).name() <br> << endl; <br><br> ptr = &derived1; <br> cout << "ptr 指向 " <br> << typeid(*ptr).name() <br> << endl; <br><br> ptr = &derived2; <br> cout << "ptr 指向 " <br> << typeid(*ptr).name() <br> << endl;<br> <br> return 0;<br>}</pre>
<span class="postbody"><br>
执行结果:</span><br>
<table style="text-align: left; width: 100%;" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="background-color: rgb(0, 0, 0);"><small><span style="color: rgb(255, 255, 255);">ptr 指向 4Base<br>
ptr 指向 8Derived1<br>
ptr 指向 8Derived2</span></small><span style="color: rgb(255, 255, 255);"><br>
</span></td>
</tr>
</tbody>
</table>
<br>
您使用共同的基底类别指标来指向基底类别物件与衍生类别物件,虽然如此,还是利用typeid()取回的type-info物件仍可以得知物件的型态名称。 <br>
<br>
RTTI的使用时机之一,就是当您将物件以参考方式传递给函式时,函式的参数使用共同的基底类别指标或参考,但在函式中有必须操作衍生类别中的某个方法,由于函式事先并不知道您传入的物件型态名称,所以您必须利用RTTI来进行判断,下面的程式是个简单的例子: <br>
<br>
<pre>#include <iostream> <br>#include <typeinfo> <br>using namespace std; <br><br>class Base { <br>public: <br> virtual void foo() = 0;<br>}; <br><br>class Derived1 : public Base { <br>public: <br> void foo() { <br> cout << "Derived1" << endl; <br> } <br> <br> void showOne() {<br> cout << "Yes! It's Derived1." << endl;<br> }<br>}; <br><br>class Derived2 : public Base { <br>public: <br> void foo() { <br> cout << "Derived2" << endl; <br> } <br> <br> void showTwo() {<br> cout << "Yes! It's Derived2." << endl;<br> }<br>}; <br><br>void showWho(Base *base) {<br> base->foo();<br> <br> if(typeid(*base) == typeid(Derived1)) {<br> Derived1 *derived1 = static_cast<Derived1*>(base);<br> derived1->showOne();<br> }<br> else if(typeid(*base) == typeid(Derived2)) {<br> Derived2 *derived2 = static_cast<Derived2*>(base);<br> derived2->showTwo(); <br> } <br>}<br><br>int main() { <br> Derived1 derived1;<br> Derived2 derived2; <br><br> showWho(&derived1);<br> showWho(&derived2);<br> <br> return 0;<br>}</pre>
<br>
<span class="postbody">执行结果:</span><br>
<table style="text-align: left; width: 100%;" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="background-color: rgb(0, 0, 0);"><small><span style="color: rgb(255, 255, 255);">Derived1<br>
Yes! It's Derived1.<br>
Derived2<br>
Yes! It's Derived2.</span></small><span style="color: rgb(255, 255, 255);"><br>
</span></td>
</tr>
</tbody>
</table>
<br>
传统的C风格转型语法也是可以使用的,例如:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">Derived1 *derived1 = (Derived1*) base;</span><br>
</div>
<br>
当然不建议使用这种方式强制转型,事实上使用static_cast也不是很适合,C++为了支援RTTI还提供有dynamic_cast,这在下一个主题中介绍。<br>
<br>
<br>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -