关于static_cast的问题
Questions about static_cast
我写了一段代码,但我对它的输出感到困惑:
#include <iostream>
using namespace std;
class B{
public:
virtual void foo() {cout << "B::foo" << endl;}
};
class D:public B{
public:
virtual void foo() {cout << "D::foo" << endl;}
void disp() {cout << "D::disp" << endl;}
};
void func(B *pb){
D *pd1 = static_cast<D*>(pb);
pd1->foo();
pd1->disp();
}
int main(int argc, char *argv[])
{
B* pb = new B();
func(pb);
return 0;
}
输出为:
B::foo
D::disp
但据我所知,pb
指向类型B。其中没有名为disp()
的函数?那么,为什么它可以访问D类中的disp()
函数呢?
由于disp()
不访问类的任何成员,原则上它与在全局命名空间中而不是在类中声明的一样,因此即使实例不是正确的类,调用它也没有负面影响。
您正在做的是将基类的指针向下转换为派生类的指针,即使它没有初始化为派生类。如果disp()
试图访问D
中但不在B
中的类成员,则可能会遇到segfault。
最重要的是:不要使用static_cast
进行下转换,除非您绝对确定指针实际上指向派生类的实例。如果您不确定,可以使用dynamic_cast
,它在不匹配的情况下会失败(但存在RTTI的开销,因此如果可以的话,请避免它)。
如果强制转换不正确或抛出std::bad_cast
,dynamic_cast
将返回nullptr
如果它强制转换引用,则会出现异常,这样您就可以确切地知道它失败的原因,而不是可能的内存损坏错误。
行:
D *pd1 = static_cast<D*>(pb);
将进行强制转换,而不管源指针是B*
还是D*
。在您的情况下,结果将是指向错误类型的对象的指针。方法disp
将工作,因为它没有使用类D
的任何数据成员或虚拟函数。在更复杂的情况下,这将导致不稳定的行为或崩溃。
你的物体是变形的。您应该使用dynamic_cast
。
我认为,在这种情况下,重要的是成员函数disp()
并没有隐藏在D
类型的所有对象中。这是一个存在于一个地方的单一功能。并且是否有任何对象将尝试调用disp()
由代码决定。
static_cast
将生成编译器认为指向D
的指针,而不管您传递给它的指针是什么。一旦您有了指向D
的指针,编译器将允许您尝试调用disp()
。
换句话说,static_cast
不会保护您不正确地投射指针
将指向分配为B
的对象的指针强制转换为指向派生类D
的指针时,您做了一些非常糟糕的事情。标准是这样说的,重点是我的:
5.2.9静态铸造
如果类型为"pointer to cv1 B"的右值指向一个实际上是D类型对象的子对象的B,则结果指针指向D类型的封闭对象。否则,强制转换的结果是未定义的。
您通过执行static_cast
调用了未定义的行为。编译器和运行时可以做任何事情,并且在程序调用未定义的行为时仍然是兼容的。
您需要了解各种类型的C++类型转换之间的区别。
你在这里使用的是静态演员阵容,这与说"我真的不在乎它是否真的是那种类型——尽你最大的努力"是一样的。
在这种情况下,你想知道你的指针是否真的是你将其转换为的派生类型。你应该使用dynamic_cast。只有当指针的类型正确时,此强制转换才会成功。这意味着,如果失败,它将返回一个NULL指针。
你看到的行为是当你没有为工作使用正确的演员阵容时会发生的事情,虽然你可以尝试解释它,但这是你真正应该避免的事情,因为它属于未定义行为的范畴。换言之,编译器之间甚至同一编译器的不同版本之间都不可能出现相同的副作用。换句话说,避免它。
- 警告处理为错误这里有什么问题
- 最小硬币更换问题(自上而下方法)
- 为"adjacent"变量赋值时出现问题
- 我的神经网络不起作用 [XOR 问题]
- 在Ubuntu 16.04上安装Cilk时出现问题
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 编译包含字符串的代码时遇到问题
- Project Euler问题4的错误解决方案
- 问题:什么是QAbstractItemView::NoEditTriggers的反面
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 在进程中对同一管道进行读取和写入时C++管道出现问题
- 如何理解C++标准N3337中的expr.const.cast子句8
- 静态数据成员的问题-修复链接错误会导致编译器错误
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- 一个关于在C++中重载布尔运算符的问题
- 首要问题的答案让值班员搞错了
- setlocale的C++土耳其字符串问题
- 如何重构类层次结构以避免菱形问题
- 基于boost的程序的静态链接——zlib问题
- 谁能帮助确定为什么这不能正确执行?如果问题与cast