Investment类有一个其他类没有的额外操作
所以运行时知道Security指针是否引用了Investment对象是很重要的
为了实现检查运行时的类型转换
每个类都持有一个整数标识符
以便可以与层次结构中其他的类区别开来
//: C08:CheckedCast.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// Checks casts at runtime.
#include <iostream>
#include <vector>
#include "../purge.h"
using namespace std;
class Security {
protected:
enum { BASEID = 0 };
public:
virtual ~Security() {}
virtual bool isA(int id) { return (id == BASEID); }
};
class Stock : public Security {
typedef Security Super;
protected:
enum { OFFSET = 1, TYPEID = BASEID + OFFSET };
public:
bool isA(int id) {
return id == TYPEID || Super::isA(id);
}
static Stock* dynacast(Security* s) {
return (s->isA(TYPEID)) ? static_cast<Stock*>(s) : 0;
}
};
class Bond : public Security {
typedef Security Super;
protected:
enum { OFFSET = 2, TYPEID = BASEID + OFFSET };
public:
bool isA(int id) {
return id == TYPEID || Super::isA(id);
}
static Bond* dynacast(Security* s) {
return (s->isA(TYPEID)) ? static_cast<Bond*>(s) : 0;
}
};
class Investment : public Security {
typedef Security Super;
protected:
enum { OFFSET = 3, TYPEID = BASEID + OFFSET };
public:
bool isA(int id) {
return id == TYPEID || Super::isA(id);
}
static Investment* dynacast(Security* s) {
return (s->isA(TYPEID)) ?
static_cast<Investment*>(s) : 0;
}
void special() {
cout << "special Investment function" << endl;
}
};
class Metal : public Investment {
typedef Investment Super;
protected:
enum { OFFSET = 4, TYPEID = BASEID + OFFSET };
public:
bool isA(int id) {
return id == TYPEID || Super::isA(id);
}
static Metal* dynacast(Security* s) {
return (s->isA(TYPEID)) ? static_cast<Metal*>(s) : 0;
}
};
int main() {
vector<Security*> portfolio;
portfolio.push_back(new Metal);
portfolio.push_back(new Investment);
portfolio.push_back(new Bond);
portfolio.push_back(new Stock);
for(vector<Security*>::iterator it = portfolio.begin();
it != portfolio.end(); ++it) {
Investment* cm = Investment::dynacast(*it);
if(cm)
cm->special();
else
cout << "not an Investment" << endl;
}
cout << "cast from intermediate pointer:" << endl;
Security* sp = new Metal;
Investment* cp = Investment::dynacast(sp);
if(cp) cout << " it's an Investment" << endl;
Metal* mp = Metal::dynacast(sp);
if(mp) cout << " it's a Metal too!" << endl;
purge(portfolio);
getchar();
} ///:~
输出
special Investment function
special Investment function
not an Investment
not an Investment
cast from intermediate pointer:
it's an Investment
it's a Metal too!
多态isA()函数检查其参数是否与它的类型参数 id 相容
意味着或者id与对象的typeID准确地匹配
或者与对象的祖先之一的类型匹配
函数dynacast()在每个类中都是静态的
dynacast()为其指针参数调用isA()来检查类型转换是否有效
借助dynamic_cast操作符
C++提供可检查的类型转换
//: C08:Security.h
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
#ifndef SECURITY_H
#define SECURITY_H
#include <iostream>
class Security {
public:
virtual ~Security() {}
};
class Stock : public Security {};
class Bond : public Security {};
class Investment : public Security {
public:
void special() {
std::cout << "special Investment function" <<std::endl;
}
};
class Metal : public Investment {};
#endif // SECURITY_H ///:~
大部分的代码开销用在了类型转换检查上
如同其他C++类型转换 static_cast 一样
dynamic_cast的目标类型放在一对尖括号中
并且转换对象以操作数的方式出现
用引用而非指针同样也可以使用dynamic_cast
由于没有诸如空引用这样的情况
需要采用其他方法来了解类型转换是否失败
//: C08:CatchBadCast.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
#include <typeinfo>
#include "Security.h"
using namespace std;
int main() {
Metal m;
Security& s = m;
try {
Investment& c = dynamic_cast<Investment&>(s);
cout << "It's an Investment" << endl;
} catch(bad_cast&) {
cout << "s is not an Investment type" << endl;
}
try {
Bond& b = dynamic_cast<Bond&>(s);
cout << "It's a Bond" << endl;
} catch(bad_cast&) {
cout << "It's not a Bond type" << endl;
}
getchar();
} ///:~
输出
It's an Investment
It's not a Bond type
bad_cast类在<typeinfo>头文件中定义
并且像标准库的大多数类一样
在std名字空间中声明