常规投放与static_cast与dynamic_cast
660456 观看
8回复
这个问题已经在这里有了答案:
我从事C和C ++代码已有近20年的历史了,但是这些语言的一个方面我从未真正理解过。我显然使用过常规演员
MyClass *m = (MyClass *)ptr;
各地,但似乎还有其他两种类型的演员,我不知道两者之间的区别。以下几行代码有什么区别?
MyClass *m = (MyClass *)ptr;
MyClass *m = static_cast<MyClass *>(ptr);
MyClass *m = dynamic_cast<MyClass *>(ptr);
作者: Graeme Perrow
的来源
发布者: 2019 年 9 月 29 日
回应 (8)
1523像
的static_cast
static_cast
用于基本要撤消隐式转换,但有一些限制和附加的情况。static_cast
不执行任何运行时检查。如果您知道引用了特定类型的对象,则应使用此方法,这样就不必进行检查了。例:
void func(void *data) {
// Conversion from MyClass* -> void* is implicit
MyClass *c = static_cast<MyClass*>(data);
...
}
int main() {
MyClass c;
start_thread(&func, &c) // func(&c) will be called
.join();
}
在此示例中,您知道您传递了一个MyClass
对象,因此不需要任何运行时检查来确保这一点。
的dynamic_cast
dynamic_cast
当您不知道对象的动态类型是什么时很有用。如果所引用的对象不包含强制转换为基类的类型,则它返回一个空指针(当强制转换为引用时,bad_cast
在这种情况下将引发异常)。
if (JumpStm *j = dynamic_cast<JumpStm*>(&stm)) {
...
} else if (ExprStm *e = dynamic_cast<ExprStm*>(&stm)) {
...
}
不能使用dynamic_cast
,如果你垂头丧气(转换为派生类)和参数类型不是多态。例如,以下代码无效,因为其中Base
不包含任何虚函数:
struct Base { };
struct Derived : Base { };
int main() {
Derived d; Base *b = &d;
dynamic_cast<Derived*>(b); // Invalid
}
同时使用static_cast
和时dynamic_cast
,“向上转换”(转换为基类)始终有效,并且也无需任何强制转换,因为“向上转换”是隐式转换。
常规演员
这些转换也称为C样式转换。C样式的强制转换基本上与尝试一系列C ++强制转换序列相同,并且无需考虑即可获得第一个有效的C ++强制转换dynamic_cast
。不用说,这是更强大,因为它结合了所有的const_cast
,static_cast
和reinterpret_cast
,但它也是不安全的,因为它不使用dynamic_cast
。
另外,C样式强制转换不仅允许您执行此操作,而且还允许您安全地强制转换为私有基类,而“等效” static_cast
序列将为此提供编译时错误。
由于简洁,有些人喜欢使用C型演员表。我仅将它们用于数字转换,并在涉及用户定义类型时使用适当的C ++转换,因为它们提供了更严格的检查。
作者: Johannes Schaub - litb 发布者: 10.08.2009 01:50158像
静态演员
静态类型转换在兼容类型之间执行转换。它类似于C样式的强制类型转换,但更具限制性。例如,C样式强制转换将允许整数指针指向char。
char c = 10; // 1 byte
int *p = (int*)&c; // 4 bytes
由于这会导致一个4字节的指针指向分配的内存的1字节,因此对该指针进行写入将导致运行时错误或覆盖某些相邻的内存。
*p = 5; // run-time error: stack corruption
与C样式强制转换相反,静态强制转换将允许编译器检查指针和指针数据类型是否兼容,从而允许程序员在编译期间捕获此错误的指针分配。
int *q = static_cast<int*>(&c); // compile-time error
重新诠释演员表
为了强制进行指针转换,就像在后台使用C样式强制转换一样,将使用重新解释强制转换。
int *r = reinterpret_cast<int*>(&c); // forced conversion
此强制转换处理某些不相关的类型之间的转换,例如从一种指针类型到另一种不兼容的指针类型。它将仅执行数据的二进制副本,而不更改基础位模式。注意,这种低级操作的结果是特定于系统的,因此不可移植。如果不能完全避免,则应谨慎使用。
动态投放
这个仅用于将对象指针和对象引用转换为继承层次结构中的其他指针或引用类型。它是通过执行运行时检查来确保指针所指向的对象可以转换为目标类型的完整对象的唯一转换。为了使运行时检查成为可能,对象必须是多态的。也就是说,该类必须定义或继承至少一个虚函数。这是因为编译器只会为此类对象生成所需的运行时类型信息。
动态演员表示例
在下面的示例中,使用动态强制转换将MyChild指针转换为MyBase指针。由于Child对象包括完整的Base对象,因此这种派生到基本的转换成功。
class MyBase
{
public:
virtual void test() {}
};
class MyChild : public MyBase {};
int main()
{
MyChild *child = new MyChild();
MyBase *base = dynamic_cast<MyBase*>(child); // ok
}
下一个示例尝试将MyBase指针转换为MyChild指针。由于基础对象不包含完整的子对象,因此该指针转换将失败。为了表明这一点,动态转换返回一个空指针。这提供了一种方便的方法来检查运行时转换是否成功。
MyBase *base = new MyBase();
MyChild *child = dynamic_cast<MyChild*>(base);
if (child == 0)
std::cout << "Null pointer returned";
如果转换了引用而不是指针,则动态转换将因抛出bad_cast异常而失败。这需要使用try-catch语句来处理。
#include <exception>
// …
try
{
MyChild &child = dynamic_cast<MyChild&>(*base);
}
catch(std::bad_cast &e)
{
std::cout << e.what(); // bad dynamic_cast
}
动态或静态转换
使用动态强制转换的优点在于,它允许程序员检查运行时转换是否成功。缺点是执行此检查会产生性能开销。出于这个原因,在第一个示例中使用静态转换将是更可取的,因为从派生到基本的转换将永远不会失败。
MyBase *base = static_cast<MyBase*>(child); // ok
但是,在第二个示例中,转换可能成功或失败。如果MyBase对象包含MyBase实例,它将失败;如果包含MyChild实例,则它将成功。在某些情况下,可能要等到运行时才能知道。在这种情况下,动态投射比静态投射更好。
// Succeeds for a MyChild object
MyChild *child = dynamic_cast<MyChild*>(base);
如果从基到源的转换是使用静态转换而不是动态转换执行的,则转换不会失败。它将返回一个指向不完整对象的指针。取消引用此类指针可能会导致运行时错误。
// Allowed, but invalid
MyChild *child = static_cast<MyChild*>(base);
// Incomplete MyChild object dereferenced
(*child);
const cast
此代码主要用于添加或删除变量的const修饰符。
const int myConst = 5;
int *nonConst = const_cast<int*>(&myConst); // removes const
尽管const cast允许更改常量的值,但这样做仍然是无效代码,可能会导致运行时错误。例如,如果常量位于只读存储器的一部分中,则可能会发生这种情况。
*nonConst = 10; // potential run-time error
相反,const转换主要在有一个采用非恒定指针参数的函数时使用,即使该函数不会修改指针。
void print(int *p)
{
std::cout << *p;
}
然后可以通过使用const强制将函数传递给常量变量。
print(&myConst); // error: cannot convert
// const int* to int*
print(nonConst); // allowed
作者: Breeze
发布者: 24.08.2013 01:55
78像
您应该查看文章C ++编程/类型转换。
它很好地描述了所有不同的演员类型。以下摘自上述链接:
作者: TJ Seabrooks 发布者: 26.08.2008 01:28const_cast会
const_cast(expression)const_cast <>()用于添加/删除变量的const(ness)(或volatile-ness)。
的static_cast
static_cast(expression)static_cast <>()用于在整数类型之间进行转换。'例如'char-> long,int-> short等。
静态转换还用于将指针转换为相关类型,例如将void *转换为适当的类型。
的dynamic_cast
动态强制转换用于在运行时转换指针和引用,通常目的是在继承链(继承层次结构)的上方或下方强制转换指针或引用。
dynamic_cast的(表达)
目标类型必须是指针或引用类型,并且表达式必须计算为指针或引用。仅当表达式引用的对象类型与目标类型兼容并且基类具有至少一个虚拟成员函数时,动态转换才起作用。如果不是,并且正在转换的表达式类型是一个指针,则返回NULL,如果对引用的动态转换失败,则会引发bad_cast异常。当它没有失败时,动态类型转换将把目标类型的指针或引用返回到表达式所引用的对象。
reinterpret_cast的
重新解释类型转换只是将一种类型按位转换为另一种类型。任何指针或整数类型都可以通过重新解释转换而转换为其他任何类型,很容易导致滥用。例如,使用重新解释转换,可能会不安全地将整数指针转换为字符串指针。
27像
避免使用C样式强制转换。
C样式强制转换是const和重新解释强制转换的混合体,很难在代码中查找和替换。C ++应用程序程序员应避免使用C样式强制转换。
作者: ugasoft 发布者: 19.09.2008 05:3027像
仅供参考,我相信Bjarne Stroustrup的话是要避免使用C风格的强制转换,如果可能的话,应该使用static_cast或dynamic_cast。
采纳您的建议。我远不是C ++专家。
作者: Jason Baker 发布者: 26.08.2008 01:3915像
C样式转换将const_cast,static_cast和reinterpret_cast合并在一起。
我希望C ++没有C样式的强制转换。C ++强制转换正确地突出了(应有的表现;强制转换通常表示做错了事),并正确区分了强制转换执行的不同类型的转换。它们还允许编写外观相似的函数,例如boost :: lexical_cast,从一致性角度来看,这是相当不错的。
作者: DrPizza 发布者: 26.08.2008 01:3811像
dynamic_cast
具有运行时类型检查,并且仅与引用和指针一起使用,static_cast
而不提供运行时类型检查。有关完整的信息,请参见MSDN文章static_cast Operator。
11像
dynamic_cast
仅支持指针和引用类型。NULL
如果类型是指针,则返回强制转换是否可能;如果类型是引用类型,则抛出异常。因此,dynamic_cast
可以用来检查对象是否为给定类型,static_cast
不能(给您一个无效值)。
其他答案涵盖了C样式(和其他)强制类型转换。
作者: larsmoa 发布者: 05.02.2012 05:10来自类别的问题 :
- c++ 理解指针有什么障碍,克服它们可以做些什么?
- c++ 在C ++中解析INI文件的最简单方法是什么?
- c++ 什么时候应该在C ++中使用“朋友”?
- c++ 你如何清除stringstream变量?
- c++ 在C ++中,构造函数和析构函数可以是内联函数吗?
- c++ 在C ++中,什么是虚拟基类?
- pointers How do you pass a function as a parameter in C?
- pointers 常规投放与static_cast与dynamic_cast
- pointers C ++中的指针变量和引用变量之间有什么区别?
- pointers 为什么不能在C中将'char **'转换为'const char * const *'?
- pointers 什么是智能指针,什么时候应该使用?
- casting 在C#中将int转换为枚举
- casting C ++强制转换语法样式
- casting 在.NET 2.0中将List <int>转换为List <string>
- casting 为什么使用static_cast <int>(x)而不是(int)x?
- casting 直接铸造与“ as”运算符?