dynamic_cast—多态类型的转化
表达式:dynamic_cast(expression)把操作数expression转化为一个type-id对象。type-id必须是一个指针或者是一个引用。如果type-id是一个指针,那么expression必须是一个指针。如果type-id是一个引用,那么expression是一个左值表达式。
如果type-id是一个指针,这个指针指向的是expression的直接或者间接基类,那么指向唯一父类对象的type-id是最终结果。(例如)
class B { ... };
class C : public B { ... };
class D : public C { ... };
void f(D* pd)
{
C* pc = dynamic_cast(pd); // ok: C is a direct base class
// pc points to C subobject of pd
B* pb = dynamic_cast(pd); // ok: B is an indirect base class
// pb points to B subobject of pd
...
}
这种类型的转化称为”向上转换”(upcast),因为它将指针向类的层次关系的上层移动。Upcast是一种隐式的转化。
如果type-id是void *,运行时检查会确定expression的实际的类型。结果由expression指向的完整的指针对象。
class A { ... };
class B { ... };
void f()
{
A* pa = new A;
B* pb = new B;
void* pv = dynamic_cast(pa);
// pv now points to an object of type A
...
pv = dynamic_cast(pb);
// pv now points to an object of type B
}
如果type-id不是void *,那么运行时会检查由expression指向的对象是否能够转化为由type-id指向的对象。
如果expression的类型是type-id类型的基类,运行时检查会确保expression是否实际上指向一个type-id的完整的对象。如果为true,那么结果为type-id所指向的完整的对象。例如:
class B { ... };
class D : public B { ... };
void f()
{
B* pb = new D; // unclear but ok
B* pb2 = new B;
D* pd = dynamic_cast(pb); // ok: pb actually points to a D
...
D* pd2 = dynamic_cast(pb2); // pb2 points to a B not a D
// cast was bad so pd2 == NULL
...
}
这种类型的转化称为“downcast”—向下转型。因为它从类的层次结构中向下移动。从一个指定的父类到子类。
对于多继承关系,模糊的情况产生了。考察下面的类层次关系。
Class Hierarchy Showing Multiple Inheritance
类型D的对象能够安全的转化为B或者C。然而D如果转化为A,那么它将转化为哪个A?这将产生一个有歧义的转化错误。为了解决这个问题,你可以执行两个无歧义的转化。例如:
void f()
{
D* pd = new D;
A* pa = dynamic_cast(pd); // error: ambiguous
B* pb = dynamic_cast(pd); // first cast to B
A* pa2 = dynamic_cast(pb); // ok: unambiguous
}
当使用了虚拟基类的时候,可能会产生新的歧义问题。考查一下下面的层次结构
Class Hierarchy Showing Virtual Base Classes
在此层次结构中,A为虚拟基类。给定一个类E的实例和指向子对象A的指针,dynamic_cast转化为指针B将因为歧义而失败。首先应当转化为完整的E对象,根据继承链,选择一种清晰的方式,到达正确的B对象。
考虑一下的类层次结构
Consider the class hierarchy shown in the following figure.
Class Hierarchy Showing Duplicate Base Classes
给定一个对象类型E和一个指向D子对象。从D到左边的A,有三种转化方式。你可以从DEBA。例如:
void f(D* pd)
{
E* pe = dynamic_cast(pd);
B* pb = pe; // upcast, implicit conversion
A* pa = pb; // upcast, implicit conversion
}
dynamic_cast操作符也能够用来执行“cross cast”.使用相同的类层次。能够从指针BD,只要对象是完整的E对象。
考虑到交叉转化。DA只需要两步。你可以从DB,然后隐式转化为A。例如:
void f(D* pd)
{
B* pb = dynamic_cast(pd); // cross cast
A* pa = pb; // upcast, implicit conversion
}
通过dynamic_cast,将一个null指针转化为目标类型的null指针值。
当你使用dynamic_cast < type-id > ( expression)。如果expression不能够安全的转化为type-id类型,此种转化是失败的。
class A { ... };
class B { ... };
void f()
{
A* pa = new A;
B* pb = dynamic_cast(pa); // fails, not safe;
// B not derived from A
...
}
指针通过dynamic_cast转化失败为null指针,引用转化失败将抛出一个bad_cast 异常。如果express不能够指向一个正确的对象的引用,那么__non_rtti_object异常将抛出。
static_cast非多态类型转化
static_cast操作符将expression转化为type-id类型。没有运行时检查来确保这项转化是安全的转化。
static_cast操作符可以用来将基类的指针转化为派生类的指针,这样的转化都不总是安全的。
一般的,可以使用static_cast来将数字数据类型(enums)转化为ints,或者将ints转化为floats.你能够确保数据类型包含在转化之中。static_cast没有dynamic_cast安全。因为static_cast没有运行时检查。当遇到有歧义的指针时,dynamic_cast会失败,而static_cast将返回,好像没有任何错误一样。这是非常危险的。虽然dynamic_cast是安全的,但是它仅适用于指针和引用,并且运行时检查是一个负担。
class B { ... };
class D : public B { ... };
void f(B* pb, D* pd)
{
D* pd2 = static_cast(pb); // not safe, pb may
// point to just B
B* pb2 = static_cast(pd); // safe conversion
...
}
与dynamic_cast相比,static_cast转化pb没有运行时检查。由pb指向的对象可能不是类型D的对象。使用*pd2将是灾难性的。例如,调用类D的一个成员函数,但不是B的成员函数,将导致访问错误。
dynamic_cast和static_cast操作符在类的层次中移动指针。但是static_cast依靠cast语句中的信息排除因此是不安全的。
class B { ... };
class D : public B { ... };
void f(B* pb)
{
D* pd1 = dynamic_cast(pb);
D* pd2 = static_cast(pb);
}
如果pb是指向类型D的指针,那么pd1和pd2将得到相同的值。如果pb==0,那么他们也得到相同的值。
如果pb指向对象类型B,不是完整的D类。dynamic_cast将返回0,然而static_cast依赖于程序员的断言,pb指向一个类型D的对象并且简单的返回一个指针指向假想的D对象。
随后,static_cast能够做这个隐式的转化,结果是没有定义的。需要程序员来确保static_cast转化是安全的。
这种行为可以应用于类型而不仅仅是类类型。例如,static_cast能够用来将一个int转化为char,然而,char可能没有足够的比特来存储整个int值。由程序员来确保这种行为的安全性。
satic_cast操作符可以用来执行任何隐式的转化,包括标准的转化和用户定义的转化。例如:
typedef unsigned char BYTE
void f()
{
char ch;
int i = 65;
float f = 2.5;
double dbl;
ch = static_cast(i); // int to char
dbl = static_cast(f); // float to double
...
i = static_cast(ch);
...
}
static_cast操作符能够显式的将一个整型值转化为枚举类型。如果整型的数值不在枚举类型的值范围内。枚举的值是undefined.
static_cast操作符将null指针转化为null指针。
通过static_cast,一个类型能够显式的转化为void类型。目标的void类型能够有选择的包括const,volatile或者_unaligned属性。
const_cast
cosnt_cast用来移除const,volatile和_unaligned属性。
const_cast操作符能够用来移除类中的const,volatile和_unaligned属性。
一个任何对象类型的指针或者一个数据成员的指针能够显示的转化为相同的类型,除了const,volatile和_unaligned标识符。对于指针和引用,结果将引用原始的对象。对于数据成员指针,结果将指向原始数据指针所指向的数据成员。依靠引用对象的雷ixng,一个结果指针(引用、数据成员)的写操作将产生undefined行为。
不能使用const_cast操作符来直接覆盖const变量的const状态。
#include
using namespace std;
class CCTest {
public:
void setNumber( int );
void printNumber() const;
private:
int number;
};
void CCTest::setNumber( int num ) { number = num; }
void CCTest::printNumber() const {
cout << "\nBefore: " << number;
const_cast< CCTest * >( this )->number--;
cout << "\nAfter: " << number;
}
void main() {
CCTest X;
X.setNumber( 8 );
X.printNumber();
}
在包含const_cast的行,数据类型this指针是const CCTest *。const_cast操作符改变this的数据类型为CCTest *,允许数据成员number被修改。
reinterpret_cast
用来简单的重新解释bits.
reinterpret_cast操作符允许任何指针转化为任何其他的指针类型。它允许任何整型类型转化为任何指针类型,反方向也一样。误用reinterpret_cast操作符是不安全的。除非需要的转化是固有的低级别的。
reinterpret_cast操作符用来将char * 转化为int *或者One_class*转化为Unrelated_class*,这样是内在的不安全的。
reinterpret_cast的结果不能够安全的使用除了转化为它的原始类型。其它的使用都是不可移植的。
reinterpret_cast操作符不能够去除const,volatile或者__unaligned属性,可以用const_cast来去除。
reinterpret_cast操作符将null指针转化为null指针。
一个实际的使用是在hash函数中使用reinterpret_cast。
#include
unsigned short Hash( void *p )
// Returns a hash code based on an address
{
unsigned int val = reinterpret_cast( p );
return ( unsigned short )( val ^ (val >> 16));
}
using namespace std;
void main()
{
int a[20];
for ( int i = 0; i < 20; i++ )
cout << Hash( a + i ) << endl;
}
reinterpret_cast操作符允许指针当作整型数值。
2007-06-25 yawer 转载请注明,谢谢!
表达式:dynamic_cast
如果type-id是一个指针,这个指针指向的是expression的直接或者间接基类,那么指向唯一父类对象的type-id是最终结果。(例如)
class B { ... };
class C : public B { ... };
class D : public C { ... };
void f(D* pd)
{
C* pc = dynamic_cast
// pc points to C subobject of pd
B* pb = dynamic_cast(pd); // ok: B is an indirect base class
// pb points to B subobject of pd
...
}
这种类型的转化称为”向上转换”(upcast),因为它将指针向类的层次关系的上层移动。Upcast是一种隐式的转化。
如果type-id是void *,运行时检查会确定expression的实际的类型。结果由expression指向的完整的指针对象。
class A { ... };
class B { ... };
void f()
{
A* pa = new A;
B* pb = new B;
void* pv = dynamic_cast
// pv now points to an object of type A
...
pv = dynamic_cast
// pv now points to an object of type B
}
如果type-id不是void *,那么运行时会检查由expression指向的对象是否能够转化为由type-id指向的对象。
如果expression的类型是type-id类型的基类,运行时检查会确保expression是否实际上指向一个type-id的完整的对象。如果为true,那么结果为type-id所指向的完整的对象。例如:
class B { ... };
class D : public B { ... };
void f()
{
B* pb = new D; // unclear but ok
B* pb2 = new B;
D* pd = dynamic_cast
...
D* pd2 = dynamic_cast
// cast was bad so pd2 == NULL
...
}
这种类型的转化称为“downcast”—向下转型。因为它从类的层次结构中向下移动。从一个指定的父类到子类。
对于多继承关系,模糊的情况产生了。考察下面的类层次关系。
Class Hierarchy Showing Multiple Inheritance
类型D的对象能够安全的转化为B或者C。然而D如果转化为A,那么它将转化为哪个A?这将产生一个有歧义的转化错误。为了解决这个问题,你可以执行两个无歧义的转化。例如:
void f()
{
D* pd = new D;
A* pa = dynamic_cast(pd); // error: ambiguous
B* pb = dynamic_cast(pd); // first cast to B
A* pa2 = dynamic_cast(pb); // ok: unambiguous
}
当使用了虚拟基类的时候,可能会产生新的歧义问题。考查一下下面的层次结构
Class Hierarchy Showing Virtual Base Classes
在此层次结构中,A为虚拟基类。给定一个类E的实例和指向子对象A的指针,dynamic_cast转化为指针B将因为歧义而失败。首先应当转化为完整的E对象,根据继承链,选择一种清晰的方式,到达正确的B对象。
考虑一下的类层次结构
Consider the class hierarchy shown in the following figure.
Class Hierarchy Showing Duplicate Base Classes
给定一个对象类型E和一个指向D子对象。从D到左边的A,有三种转化方式。你可以从DEBA。例如:
void f(D* pd)
{
E* pe = dynamic_cast
B* pb = pe; // upcast, implicit conversion
A* pa = pb; // upcast, implicit conversion
}
dynamic_cast操作符也能够用来执行“cross cast”.使用相同的类层次。能够从指针BD,只要对象是完整的E对象。
考虑到交叉转化。DA只需要两步。你可以从DB,然后隐式转化为A。例如:
void f(D* pd)
{
B* pb = dynamic_cast(pd); // cross cast
A* pa = pb; // upcast, implicit conversion
}
通过dynamic_cast,将一个null指针转化为目标类型的null指针值。
当你使用dynamic_cast < type-id > ( expression)。如果expression不能够安全的转化为type-id类型,此种转化是失败的。
class A { ... };
class B { ... };
void f()
{
A* pa = new A;
B* pb = dynamic_cast(pa); // fails, not safe;
// B not derived from A
...
}
指针通过dynamic_cast转化失败为null指针,引用转化失败将抛出一个bad_cast 异常。如果express不能够指向一个正确的对象的引用,那么__non_rtti_object异常将抛出。
static_cast非多态类型转化
static_cast操作符将expression转化为type-id类型。没有运行时检查来确保这项转化是安全的转化。
static_cast操作符可以用来将基类的指针转化为派生类的指针,这样的转化都不总是安全的。
一般的,可以使用static_cast来将数字数据类型(enums)转化为ints,或者将ints转化为floats.你能够确保数据类型包含在转化之中。static_cast没有dynamic_cast安全。因为static_cast没有运行时检查。当遇到有歧义的指针时,dynamic_cast会失败,而static_cast将返回,好像没有任何错误一样。这是非常危险的。虽然dynamic_cast是安全的,但是它仅适用于指针和引用,并且运行时检查是一个负担。
class B { ... };
class D : public B { ... };
void f(B* pb, D* pd)
{
D* pd2 = static_cast
// point to just B
B* pb2 = static_cast(pd); // safe conversion
...
}
与dynamic_cast相比,static_cast转化pb没有运行时检查。由pb指向的对象可能不是类型D的对象。使用*pd2将是灾难性的。例如,调用类D的一个成员函数,但不是B的成员函数,将导致访问错误。
dynamic_cast和static_cast操作符在类的层次中移动指针。但是static_cast依靠cast语句中的信息排除因此是不安全的。
class B { ... };
class D : public B { ... };
void f(B* pb)
{
D* pd1 = dynamic_cast
D* pd2 = static_cast
}
如果pb是指向类型D的指针,那么pd1和pd2将得到相同的值。如果pb==0,那么他们也得到相同的值。
如果pb指向对象类型B,不是完整的D类。dynamic_cast将返回0,然而static_cast依赖于程序员的断言,pb指向一个类型D的对象并且简单的返回一个指针指向假想的D对象。
随后,static_cast能够做这个隐式的转化,结果是没有定义的。需要程序员来确保static_cast转化是安全的。
这种行为可以应用于类型而不仅仅是类类型。例如,static_cast能够用来将一个int转化为char,然而,char可能没有足够的比特来存储整个int值。由程序员来确保这种行为的安全性。
satic_cast操作符可以用来执行任何隐式的转化,包括标准的转化和用户定义的转化。例如:
typedef unsigned char BYTE
void f()
{
char ch;
int i = 65;
float f = 2.5;
double dbl;
ch = static_cast
dbl = static_cast
...
i = static_cast
...
}
static_cast操作符能够显式的将一个整型值转化为枚举类型。如果整型的数值不在枚举类型的值范围内。枚举的值是undefined.
static_cast操作符将null指针转化为null指针。
通过static_cast,一个类型能够显式的转化为void类型。目标的void类型能够有选择的包括const,volatile或者_unaligned属性。
const_cast
cosnt_cast用来移除const,volatile和_unaligned属性。
const_cast操作符能够用来移除类中的const,volatile和_unaligned属性。
一个任何对象类型的指针或者一个数据成员的指针能够显示的转化为相同的类型,除了const,volatile和_unaligned标识符。对于指针和引用,结果将引用原始的对象。对于数据成员指针,结果将指向原始数据指针所指向的数据成员。依靠引用对象的雷ixng,一个结果指针(引用、数据成员)的写操作将产生undefined行为。
不能使用const_cast操作符来直接覆盖const变量的const状态。
#include
using namespace std;
class CCTest {
public:
void setNumber( int );
void printNumber() const;
private:
int number;
};
void CCTest::setNumber( int num ) { number = num; }
void CCTest::printNumber() const {
cout << "\nBefore: " << number;
const_cast< CCTest * >( this )->number--;
cout << "\nAfter: " << number;
}
void main() {
CCTest X;
X.setNumber( 8 );
X.printNumber();
}
在包含const_cast的行,数据类型this指针是const CCTest *。const_cast操作符改变this的数据类型为CCTest *,允许数据成员number被修改。
reinterpret_cast
用来简单的重新解释bits.
reinterpret_cast操作符允许任何指针转化为任何其他的指针类型。它允许任何整型类型转化为任何指针类型,反方向也一样。误用reinterpret_cast操作符是不安全的。除非需要的转化是固有的低级别的。
reinterpret_cast操作符用来将char * 转化为int *或者One_class*转化为Unrelated_class*,这样是内在的不安全的。
reinterpret_cast的结果不能够安全的使用除了转化为它的原始类型。其它的使用都是不可移植的。
reinterpret_cast操作符不能够去除const,volatile或者__unaligned属性,可以用const_cast来去除。
reinterpret_cast操作符将null指针转化为null指针。
一个实际的使用是在hash函数中使用reinterpret_cast。
#include
unsigned short Hash( void *p )
// Returns a hash code based on an address
{
unsigned int val = reinterpret_cast
return ( unsigned short )( val ^ (val >> 16));
}
using namespace std;
void main()
{
int a[20];
for ( int i = 0; i < 20; i++ )
cout << Hash( a + i ) << endl;
}
reinterpret_cast操作符允许指针当作整型数值。
2007-06-25 yawer 转载请注明,谢谢!