《跨界》尝试使用 static_cast 失败;为什么? [英] "Cross-cast" attempt using static_cast failing; why?

查看:351
本文介绍了《跨界》尝试使用 static_cast 失败;为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么交叉投射"不起作用?

以下创建此对象继承模型:

 食物/\芝士蛋糕

这里我尝试将 static_cast 指针从 cheese 指向 cake,制作一个芝士蛋糕 :D.我从 Apple Clang/LLVM 收到以下错误:

<块引用>

 错误:不允许从 'Cheese *' 到 'Cake *' 的静态转换,这与继承无关

但他们是通过继承联系起来的:他们是兄弟姐妹.

为什么我不能将 cheese 转换为 cake,就像我将 int 转换为 float 一样>?为什么我不能从继承自同一基类的派生对象交叉转换"?

最小、完整且可验证的示例如下,包括 static_castdynamic_cast 尝试,以突出显示错误.

#include #include <字符串>类食品{上市:食品(标准::字符串品牌):品牌_(品牌){}虚拟 ~Food() {};std::string 品牌(){ 返回品牌_;}virtual void cut()const { std::cout <<切菜."<<std::endl;}voideat()const { std::cout <<吃的东西."<<std::endl;}私人的:std::string 品牌_;};奶酪类:公共食品{上市:奶酪(标准::字符串品牌):食物(品牌){};virtual void cut()const { std::cout <<"奶酪切块.\n";}voideat()const { std::cout <<"奶酪被吃掉了.\n";}};蛋糕类:公共食品{上市:蛋糕(标准::字符串品牌):食物(品牌){};virtual void cut()const { std::cout <<"切蛋糕.\n";}voideat()const { std::cout <<"蛋糕吃完了.\n";}};int main() {食物 f("tbd");奶酪 c("切达干酪");蛋糕 cc("芝士蛋糕");食物 * food_ptr;奶酪 *cheese_ptr, *cheeseCake_ptr;蛋糕 *cake_ptr;food_ptr = &f;food_ptr->cut();//->切菜."food_ptr = &c;food_ptr->cut();//->切奶酪."虚拟关键字的结果.cheese_ptr = dynamic_cast<奶酪*>(food_ptr);cheese_ptr->cut();//->切奶酪."沮丧的工作food_ptr = &cc;cake_ptr = dynamic_cast<蛋糕*>(food_ptr);cake_ptr->cut();//->切蛋糕."指针重新分配和向下转换有效.cheeseCake_ptr = dynamic_cast<奶酪*>(food_ptr);cheeseCake_ptr->cut();//->切蛋糕."同样,Food* 动态转换为 Cheese*/* ~~~ 注意:下面的例子故意抛出错误~~~ *//*动态交叉投射尝试:错误:从不兼容的类型蛋糕 *"分配给奶酪 *"动态转换:没有意义,因为奶酪和蛋糕之间的关系不是多态的*/cheeseCake_ptr = dynamic_cast(cheese_ptr);cheeseCake_ptr->cut();/*静态交叉投射尝试:错误:不允许从Cheese *"到Cake *"的静态转换,这与继承无关静态演员:为什么这不起作用?我们知道数据类型.*/cheese_ptr = &c;cake_ptr = &cc;cheeseCake_ptr = static_cast(cheese_ptr);std::cout <<"\n\n";返回0;}

解决方案

notrelated by继承 表示在同一个分支上...

您不应该将转换值误认为是转换指针(或相反),它们是不同的类型转换.

int to float 使用一个函数将给定类型的值转换为目标类型的值(注意这个函数可以是显式的,也可以是隐式的,对于特定情况,它是隐式的,即在语言中定义).在 C++ 中,您可以通过为类 A 实现一个能够接收类型 B 的值的构造函数,或通过为类 B 实现一个返回类型 A 的值的强制转换运算符,在自定义类类型上实现这一点.

Cake *Cheese * 不会转换值,而是尝试以不同的方式查看给定的对象.它是子类型多态性(因此您需要使用 dynamic_cast).给定您的类型层次结构,通过使用 Food 指针指向 Cheese 对象,可以轻松地将 Cheese 对象视为(而不是转换)为 Food 对象(就像您可以被不同的人以不同的方式看待一样,(想想朋友,教授的方式)或者医生可以逮捕你,而你总是同一个人!)很明显(至少在你的层次结构中)奶酪不能被视为蛋糕,如果奶酪对象会如何反应Cake的具体方法?你是动物,也是狗,但很难想象我能把你看成狗(你不是有4条腿吗?...

不要被你的情况所迷惑.好吧,看起来 Cheese 和 Cake 的内容是一样的,但是给定的层次结构说明了事实:不在同一个分支上,你不能从 Cake 指针中得到 Cheese 指针.C++ 编译器可保护您免受此攻击.

现在,如果您使用多重继承,例如继承自 Cheese 和 Cake 的 CheeseCake,情况会略有不同.然后给定通过 Cheese 指针查看的 CheeseCake 对象,可以将其转换为 Cake 指针,因为 CheeseCake 两者兼而有之!当然,即使在那种多重继承场景中,也不能通过指针将 Cheese 对象视为 Cake.

Why doesn't ths "cross-cast" work?

The following creates this object inheritance model:

     FOOD
    /    \
 CHEESE  CAKE

Here I attempt to static_cast a pointer from cheese to cake, making a cheesecake :D. I am getting the following error from Apple Clang/LLVM:

 ERROR: Static cast from 'Cheese *' to 'Cake *', which are not related by inheritance, is not allowed

But they ARE related by inheritance: they are siblings.

Why can't I cast a cheese to a cake, like I cast an int to a float? Why can't I "cross-cast" from derived objects which inherit from the same base class?

Minimal, complete, and verifiable example follows, with static_cast and dynamic_cast attempts included, to highlight errors.

#include <iostream>
#include <string>

class Food {
public:
    Food(std::string brand):brand_(brand) {}
    virtual ~Food() {};
    std::string brand() { return brand_; }
    virtual void cut()const { std::cout << "Food cut." << std::endl; }
    void eat()const { std::cout << "Food eaten." << std::endl; }
private:
    std::string brand_;
};

class Cheese : public Food {
public:
    Cheese(std::string brand):Food(brand) {};
    virtual void cut()const { std::cout << "Cheese cut.\n"; }
    void eat()const { std::cout << "Cheese eaten.\n"; }
};

class Cake : public Food {
public:
    Cake(std::string brand):Food(brand) {};
    virtual void cut()const { std::cout << "Cake cut.\n"; }
    void eat()const { std::cout << "Cake eaten.\n"; }
};

int main() {
    Food f("tbd");
    Cheese c("Cheddar");
    Cake cc("Cheesecake");
    Food * food_ptr;
    Cheese *cheese_ptr, *cheeseCake_ptr;
    Cake *cake_ptr;

    food_ptr = &f;
    food_ptr->cut();  //-> "Food cut."

    food_ptr = &c;
    food_ptr->cut();  //-> "Cheese cut." Result of virtual keyword.

    cheese_ptr = dynamic_cast<Cheese*> (food_ptr);
    cheese_ptr->cut(); //-> "Cheese Cut." The downcast worked

    food_ptr = &cc;
    cake_ptr = dynamic_cast<Cake*> (food_ptr);
    cake_ptr->cut(); //-> "Cake Cut." pointer reassignment and downcast worked.


    cheeseCake_ptr = dynamic_cast<Cheese*> (food_ptr);
    cheeseCake_ptr->cut(); //-> "Cake cut." Again, Food* dynamically casted to Cheese*

    /* ~~~ NOTE: THE FOLLOWING EXAMLES INTENTIONALLY THROW ERRORS ~~~ */

    /*
     Dynamic cross-cast attempt:
     ERROR: Assigning to 'Cheese *' from incompatable type 'Cake *'
     Dynamic cast: doensn't make sense, as the relationshiop between cheese and cake is not polymorphic
    */

    cheeseCake_ptr = dynamic_cast<Cake*> (cheese_ptr);
    cheeseCake_ptr->cut();

    /*
     Static cross-cast attempt:
     ERROR: Static cast from 'Cheese *' to 'Cake *', which are not related by inheritance, is not allowed
     Static cast: why doesn't this work? We know the data types.
     */

    cheese_ptr = &c;
    cake_ptr = &cc;
    cheeseCake_ptr = static_cast<Cake*> (cheese_ptr);

    std::cout << "\n\n";
    return 0;
}

解决方案

not related by inheritance would mean on the same branch...

You should not mistake casting values for casting pointers (or the converse), they are different type conversion.

The int to float uses a function to convert a value of a given type to a value of the target type (note that this function can be explicit or implicit, it is implicit for that particular case ie. defined in the langage). In C++ you can implement this on custom class types by implementing a ctor for class A that is able to received a value of type B, or by implementing a cast operator for class B that returns a value of type A.

The Cake * to Cheese * do not convert values, but tries to view a given object in a different manner. It is sub-typing polymorphism (so you need to use dynamic_cast). Given your type hierarchy, a Cheese object can easily be viewed (not converted) as a Food object by using a Food pointer to point to a Cheese object (just like you can be viewed differently by different persons, (think the way friend, professor or doctor can apprehend you while you are always the same person!). It is clear (at least in your hierarchy) that a Cheese can't be viewed as a Cake, if it would be the case how the Cheese object would react to Cake's specific methods? You are an Animal, a Dog also, but it is difficult to imagine that I can view you as a Dog (you don't have 4 legs isn't it?...

Don't be fooled by your case. Ok it seems that the contents of Cheese and Cake are the same, but the given hierarchy tell the truth: there are not on the same branch, you can't get a Cheese pointer from a Cake pointer. C++ compiler protects you against this.

Now things change slightly if you use multiple inheritance like a CheeseCake inheriting from Cheese and Cake. Then given a CheeseCake object viewed through a Cheese pointer, it is possible to convert it to Cake pointer because a CheeseCake is both! Of course even in that multiple inheritance scenario, a Cheese object cannot be viewed as a Cake through pointers.

这篇关于《跨界》尝试使用 static_cast 失败;为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆