您的位置:首页 > 编程语言 > C语言/C++

C++中的类型转换与类型识别 2

2006-04-21 17:20 183 查看
C++ 基础内容,不值一提
Author:Jacky Wu 2006-4-17
引用该文章,须注明其出处 http://blog.csdn.net/imwkj

3:多态中的类型转换

多态中的类型转换是通过使用基类的指针或者引用来实现的,包括“向上类型转换(upcasting)”和“向下类型转换(downcasting)”,其中向下类型转换的实现是通过virtual 机制实现的,关于C++ 中virtual机制要好好理解,这里仅仅聊聊它们之中的类型转换。
a.向上类型转换 upcasting
//Inheritance & upcasting
enum note { middleC, Csharp, Eflat };
class Instrument {
public:
void play(note) const {
cout << "Instrument::play" << endl;
}
};

class Wind : public Instrument {
public:
void play(note) const {
cout << "Wind::play" << endl;
}
};

void tune(Instrument& i) {
//这里可能发生类型转换
i.play(middleC);
}
int main() {
Wind flute;
tune(flute); //传递的是Wind型对象,发生向上类型转换
}
//输出结果:
Instrument::play
在这里由于自动发生了类型转换,Wind 类型被自动转换到Instrument基类型上(只有显示继承关系才能发生这种转换),在这种情况下,显然程序输出的结果不是我们所期望的,如果想发生正确的调用就必须使用虚机制(virtual class& function)。在这里,我们只谈类型转换。我们先来看一下发生正确调用的类型转换:

//Inheritance & upcasting
enum note { middleC, Csharp, Eflat };
class Instrument {
public:
virtual void play(note) const { //只是在这里声明为虚函数
cout << "Instrument::play" << endl;
}
};

class Wind : public Instrument {
public:
void play(note) const {
cout << "Wind::play" << endl;
}
};

void tune(Instrument& i) {
//这里可能发生类型转换
i.play(middleC);
}
int main() {
Wind flute;
tune(flute); //传递的是Wind型对象,发生向上类型转换
}
输出结果:
Wind::play
这才是正确的“向上类型转换”,关于类的虚机制,我们在后面专门介绍。

b.向下类型转换(downcasting)
由于向上类型转换是安全的转换,在转换过程中会变成更一般的基类型,所以在转换后,一般不会出现错误。但向下类型转换就会出现迷惑,由一般基类型转换到子类型就会出现不清楚的问题。举个例子,Pet (宠物) 代表一个类型,Cat 和 Dog是它的派生子类,从Cat,或者Dog转换到Pet,是可以理解并正确的,但是如果是一个Pet,那如何知道它是必须转换成Cat还是Dog??这必须使用C++中的RTTI(run-time type identification) 运行时刻类型识别机制来进行处理。
有几个关键字要用到,他们是typeid , static_cast , dynamic_cast为了能够安全的进行 downcasting,我们就得学会使用这些关键字,但是更好的方法是使用C++提供的虚机制。
由于C++在考虑到了效率因素,它在类的实现中并没有给每个类额外的加上“类型信息” (class information) ,所以我们就不能直接对普通类进行转换,因此,在使用这个功能的时候,类必须是多态方式实现的(必须有virtual机制),看代码:
class Pet {
public:
virtual ~Pet() {}
};

class Dog : public Pet {};
class Cat: public Pet {};
int main() {
Pet* pt = new Cat; //Upcast
//尝试 将 pt转换为 Dog,这中转换是错误的,dg = 0
Dog* dg = dynamic_cast<Dog*> (pt);
//尝试转换为Cat,正确
Cat* ct = dynamic_cast<Cat*> (pt);
cout << " dg = " << dg << endl;
cout << " ct = " << ct << endl;
}
输出结果:
dg = 0
ct = 0x3d2480
可见,如果发生成功的dynamic_cast转换,返回得到的对象的地址,相反,失败的转换返回0,在这种情况下,我们必须对返回的结果做出判定,否则就可能会发生错误。
这样,程序会花费额外的开销,如果我们知道被转换的对象是何种类型,我们就可以使用static_cast,同时使用typeid来确保这种转换是正确的,看下面的代码:
#include <iostream>
#include <typeinfo>
using namespace std;
class Pet {
public:
virtual ~Pet() {}
};

class Dog : public Pet {};
class Cat: public Pet {};
int main() {
Dog adog;
Pet* apet = &adog; //正确的向上类型转换

Dog* dg = 0;
Cat* ct = 0;
cout << typeid(apet).name()<< endl;
cout << typeid(dg).name() << endl;
cout << typeid(ct).name() << endl;
//上面的输出结果和编译器相关
if(typeid(apet) == typeid(dg)) {//利用typeid()确定其所属类型
dg = static_cast<Dog*>(apet);
}

if(typeid(apet) == typeid(ct)) {
ct = static_cast<Cat*>(apet);
}

if(dg != 0) {
cout << "It is a Dog/n";
}
if(ct != 0) {
cout << "It is a Cat/n";
}
}
输出结果:
P3Pet
P3Dog
P3Cat

在这个程序中用了头文件<typeinfo> ,这是C++为RTTI提供支持的一个头文件。用typeid操作符来确定对象指针的所属类型,它返回的是一个指向静态type_info型对象的引用。由于static_cast , dynamic_cast不能转换到其他外部类型,所以这种转换是安全的,但是有一定的效率损失,在一般情况下我们使用dynamic_cast而不用static_cast
C++中的类型转换由于牵涉到虚机制和RTTI机制,看起来会让人感到迷惑,同时有些复杂,如果弄清楚这两个重要的内在机制在理解类型转换就会很容易。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: