Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么在这里使用静态强制转换而不是动态强制转换? 我从书中复制下面的文本,更有效的C++。< /P>_C++ - Fatal编程技术网

为什么在这里使用静态强制转换而不是动态强制转换? 我从书中复制下面的文本,更有效的C++。< /P>

为什么在这里使用静态强制转换而不是动态强制转换? 我从书中复制下面的文本,更有效的C++。< /P>,c++,C++,第31项:使多个对象的功能虚拟化。 class GameObject { ... }; class SpaceShip: public GameObject { ... }; class SpaceStation: public GameObject { ... }; class Asteroid: public GameObject { ... }; 最常见的双重分派方法是通过if-then-else链将我们返回到虚拟函数仿真的无情世界。在这个严酷的世界中,我们首先发现其他对象的真实类型,然

第31项:使多个对象的功能虚拟化。

class GameObject { ... };
class SpaceShip: public GameObject { ... };
class SpaceStation: public GameObject { ... };
class Asteroid: public GameObject { ... };
最常见的双重分派方法是通过if-then-else链将我们返回到虚拟函数仿真的无情世界。在这个严酷的世界中,我们首先发现其他对象的真实类型,然后根据所有可能性对其进行测试:

void SpaceShip::collide(GameObject& otherObject)
{
  const type_info& objectType = typeid(otherObject);

  if (objectType == typeid(SpaceShip)) {
    SpaceShip& ss = static_cast<SpaceShip&>(otherObject);

    process a SpaceShip-SpaceShip collision;

  }
  else if (objectType == typeid(SpaceStation)) {
    SpaceStation& ss =
      static_cast<SpaceStation&>(otherObject);

    process a SpaceShip-SpaceStation collision;

  }
...
}
void SpaceShip::collide(游戏对象和其他对象)
{
const type_info&objectType=typeid(其他对象);
if(objectType==typeid(太空船)){
宇宙飞船&ss=静态投射(其他物体);
处理飞船碰撞;
}
else if(objectType==typeid(SpaceStation)){
空间站与太空船=
静态投影(其他对象);
处理飞船与空间站的碰撞;
}
...
}
问题是:

Q1>为什么我们在这里使用静态强制转换而不是明显的动态强制转换

问题2> 在这种情况下它们是一样的吗

多谢各位

//更新//

事实上,我对问题2更感兴趣

比如说,

class base {};
class subclass : public base {};

base *pSubClass = new subclass;

subclass *pSubClass1 = static_cast<subClass*> (pSubClass); 
类基{};
类子类:公共基{};
base*pSubClass=新的子类;
子类*pSubClass1=静态强制转换(pSubClass);

//在这种情况下,虽然我知道我们应该在这里使用dynamic\u cast,但是静态\u cast是否正确地完成了工作?

似乎是一个非常可靠的答案。基本上,静态强制转换速度更快,但不进行运行时类型检查。

您自己已经验证了类型,因此不需要使用动态强制转换。Dynamic_cast将自动为您检查类型。

关于记录,以下是执行此操作的惯用方法:

void SpaceShip::collide(GameObject& otherObject)
{
    if (SpaceShip* ss = dynamic_cast<SpaceShip*>(&otherObject)) {
        // process a SpaceShip-SpaceShip collision;
    }
    else if (SpaceStation* ss = dynamic_cast<SpaceStation*>(&otherObject)) {
        // process a SpaceShip-SpaceStation collision;
    }

    // ...
}
void SpaceShip::collide(游戏对象和其他对象)
{
if(太空船*ss=动态投影(&otherObject)){
//处理飞船碰撞;
}
else if(SpaceStation*ss=动态投影(&otherObject)){
//处理飞船与空间站的碰撞;
}
// ...
}

它比较短,表现出相同的性能特征,最重要的是,惯用的C++不会让其他程序员从头到脚,想知道这是什么意思。


编辑(响应OP的编辑):

是的,这是定义明确的行为。以下是C++03标准第5.2.9/8节的内容:

如果存在从“指向
D
的指针”到“指向
B
的指针”的有效标准转换,则可以将类型为“指向cv1
B
”的右值转换为类型为“指向cv2
D
”的右值,其中
D
是从
B
派生的类,cv2与cv1相同或大于cv1,并且
B
不是
D
的虚拟基类。空指针值将转换为目标类型的空指针值。如果“指向cv1
B
”类型的右值指向实际上是
D
类型的对象的子对象的
B
,则生成的指针指向
D
类型的封闭对象。否则,强制转换的结果是未定义的


如果
dynamic\u cast
失败,一些编译器将生成抛出
std::bad\u cast
的代码。因此,在这种情况下,这两种方法是不同的。使用
dynamic\u cast
可能看起来像

try {
    SpaceShip& ship = dynamic_cast<SpaceShip&>(otherObject);
    // collision logic
    return;
} catch (std::bad_cast&) {}

try {
    SpaceStation& station = dynamic_cast<SpaceStation&>(otherObject);
    // collision logic
    return;
} catch (std::bad_cast&) {}
试试看{
宇宙飞船和飞船=动态投影(其他物体);
//冲突逻辑
返回;
}catch(std::bad_cast&){
试一试{
空间站和空间站=动态投影(其他对象);
//冲突逻辑
返回;
}catch(std::bad_cast&){
这看起来真的很糟糕。

为什么他们选择以这种方式实现它,而不是更传统的
动态转换
我不能说,但这两个选项的行为不一定相同。如前所述,该代码只考虑参数的实际类型,而
dynamic\u cast
考虑参数在继承树中的位置。考虑:

struct Base { virtual ~Base() { } };
struct Intermediate : Base { };
struct Derived : Intermediate { };

int main() {
    Intermediate i;
    Base* p_i = &i;

    Derived d;
    Base* p_d = &d;

    assert(typeid(*p_i) == typeid(Intermediate)); //1
    assert(dynamic_cast<Intermediate*>(p_i)); //2

    assert(typeid(*p_d) == typeid(Intermediate)); //3
    assert(dynamic_cast<Intermediate*>(p_d)); //4
}
struct Base{virtual~Base(){};
结构中间:基{};
结构派生:中间{};
int main(){
中间产物Ⅰ;
基准*p_i=&i;
导出d;
基准*p_d=&d;
断言(typeid(*p_i)=typeid(Intermediate));//1
assert(dynamic_cast(p_i));//2
断言(typeid(*p_d)=typeid(中间));//3
assert(dynamic_cast(p_d));//4
}
(1) 和(2)都通过了它们的断言,但是(3)失败,而(4)成功<代码>p_d指向一个
派生的
对象,因此
type_id
生成一个
派生的
对象的信息,该信息与
中间的
对象的信息不相等。但是
Derived
派生自
Intermediate
,因此
dynamic\u-cast
将愉快地将指向
Derived
的指针转换为指向
Intermediate
的指针

用原始问题中使用的术语来说,如果
其他物体
是一艘
护卫舰
,它源自
宇宙飞船
,它将不会使用“宇宙飞船”碰撞例程。很可能这不是预期的行为;您可能希望Frigate使用该代码,但您必须手动添加新类型的显式检查

当然,如果您只检查从未从中继承的类型,那么这种差异就消失了。或者如果你只是不想要多态行为(尽管这会使标题有点误导)。在这种情况下,这可能更有效,但这是一个巨大的实现细节,我当然不会在实践中投入资金


如果类型不是多态性的,则会出现另一个小的、基本上无关紧要的差异。在我上面的代码中,如果从
Base
中删除虚拟析构函数,(2)和(4)现在将显示未定义的行为。