【问题标题】:typeid.name() not changing when iterating through a vector. Dynamic cast and typeid a base class pointertypeid.name() 在遍历向量时不会改变。动态转换和 typeid 基类指针
【发布时间】:2018-11-29 14:10:16
【问题描述】:

答案:总之用虚函数!所以实际上不要把它当作好的设计,但为了学习目的,请阅读!

我想首先说我正在使用 c++ 和 Qt 我有一个形状指针向量(基类)

编辑:doSomething() 不是基类的成员,而是派生类的成员。这就是为什么我使用 dynamic_cast 将 Shape* 获取到 Derived* 以便我可以访问它的原因。在这一点上,我真的只是出于好奇和其他人学习 c++ 的类型系统

    #include <vector>
    using namespace std;
    vector<Shape *> vec;

我推回一些派生类的形状

    vec.push_back(new Square());
    vec.push_back(new Circle());

好的,然后我得到一个迭代器开始

    vector<Shape *>::iterator tmp = vec.begin();

这里我想遍历向量

    for(;tmp != vec.end(); ++tmp)
    {
        if(typeid(**tmp).name() == typeid(Square).name())
        {
            Square * sptr = dynamic_cast<Square *>(*tmp);
            sptr->doSomething();
        }
        else if(typeid(**tmp).name() == typeid(Circle).name())
        {
            Circle * cptr = dynamic_cast<Circle *>(*tmp);
            cptr->doSomething();
        }
    }

但是,两者都会导致 Square 输出;不是第二个圆圈。我尝试比较 typeid 的内存位置

像这样:

    &typeid(**tmp) == &typeid(Square)

对于圆形也是如此,但对于上面的情况,tmp 总是会导致正方形,并且在之后对着圆形运行时...动态转换是否对整个向量进行了某些操作我只是缺少 typeid 的某些内容吗() 有效吗?

编辑: 这是答案,感谢 user4581301(我也添加了一些东西!):

#include <iostream>
#include <vector>
#include <typeinfo>

struct Shape
{
    virtual ~Shape(){} //Something here must be virtual or pure virtual!
};

struct Circle: Shape
{
    void doSomething(){std::cout << "Circle" << std::endl;}
};
struct Square: Shape
{
    void doSomething(){std::cout << "Square" << std::endl;}
};

int main()
{
    std::vector<Shape *> vec;
    vec.push_back(new Square());
    vec.push_back(new Circle());
    std::vector<Shape *>::iterator tmp = vec.begin();

        for(;tmp != vec.end(); ++tmp)
        {
            if(&typeid(**tmp) == &typeid(Square))
            {
                Square * sptr = dynamic_cast<Square *>(*tmp);
                sptr->doSomething();
            }
            else if(&typeid(**tmp) == &typeid(Circle))
            {
                Circle * cptr = dynamic_cast<Circle *>(*tmp);
                cptr->doSomething();
            }
        }


}

【问题讨论】:

  • 您似乎走错了路。如果doSomethingShapevirtual 成员函数,则可以调用doSomething 而无需做任何体操来确定类型。如果doSomething 不是Shapevirtual 成员函数,问问自己“为什么不是?”
  • 这可以与 doSomething 一起使用,就像 virtual 函数一样。看看这个。coliru.stacked-crooked.com/a/365df4bc103ee929。如果不是virtual,那么编译本身就会失败。
  • @P.W 使用#include &lt;bits/stdc++.h&gt; 不是我们应该传递的东西。加上使用它意味着您不需要包含您已包含的任何其他内容。
  • @user4581301:这只是为了快速演示评论中的某些内容。我不会在任何答案中那样写。
  • @yosmo78 学习是对“为什么不呢?”的一个很好的回答。我和 P.W. 在同一条船上。只要CircleSquareShape 的适当多态继承者,我就无法重现任何错误:ideone.com/LU6mJo 但是在基础中没有至少一个virtual 函数......它只是行不通:ideone.com/mUYC84

标签: c++ types polymorphism


【解决方案1】:

这与 doSomething 作为 virtual 函数一样工作。如果不是virtual,那么编译本身就会失败(如果Shape 类中没有其他函数是virtual)。如果源类型不是多态的,动态转换将失败。

如果是virtual,你不需要做你正在做的事情来确定类型。让多态发挥它的魔力。您可以像这样缩短代码:

#include <iostream>
#include <vector>

class Shape { public: virtual void doSomething() {std::cout << "In Shape\n";}};
class Circle: public Shape {public: void doSomething() {std::cout << "In Circle\n";}};
class Square: public Shape {public: void doSomething() {std::cout << "In Square\n";}};

int main() {
    std::vector<Shape *> vec;
    vec.push_back(new Square);
    vec.push_back(new Circle);

    for(auto tmp = vec.begin();tmp != vec.end(); ++tmp)
    {       
        (*tmp)->doSomething();        
    }
}

【讨论】:

  • 它编译得很好,因为我不是虚拟的,甚至在基类中也没有。那是我的设计目的(不是让每个派生类都有能力完成执行的任务)。就在派生类中,让派生类的指针可以访问它
  • 如果基类中的任何个函数是virtual,它将编译。但只有doSomething 是虚拟的,它才能正常工作。
【解决方案2】:

要使动态转换起作用,基类中的任何函数都必须是虚拟的,这意味着基类必须以多态方式使用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多