错误的向下转型在派生类中

huangapple go评论63阅读模式
英文:

bad downcasting in a derived class

问题

I am the following structure. I minimized to the shortest possible way to reproduce the error:

我是以下结构。我将其最小化以尽可能简化错误的重现:

I have two level of derived class. I don't have any compilation error. The error is at the runtime:

我有两个派生类的级别。我没有任何编译错误。错误发生在运行时:

Unhandled exception at 0x00007FFF1021CF19 in base.exe: Microsoft C++
exception: std::__non_rtti_object at memory location
0x00000022B9BDF458.

在base.exe中的0x00007FFF1021CF19处未处理的异常:Microsoft C++
异常:std::__non_rtti_object,内存位置为
0x00000022B9BDF458。

Is there any suggestion?

有什么建议吗?

#include <iostream>
#include <vector>
#include <memory>

class Base {
public:
    int a;
    Base(int _a) : a(_a) {};
    virtual void print() = 0;
};

class derivedA : public Base
{
public:
    derivedA(int _a) : Base(_a) {};
    void print() { std::cout << "dA" << std::endl; }
};

class derivedB : public derivedA
{
public:
    derivedB(int _a) : derivedA(_a) {};
    void print() { std::cout << "dB" << std::endl; }
};

void construct(std::vector<derivedA*>& da_vec) {
    da_vec.push_back(std::unique_ptr<derivedA>(new derivedB(4)).get());
}

void func(derivedA& da)
{
    derivedB& db = dynamic_cast<derivedB&>(da);
    db.print();
}

int main()
{
    std::vector<derivedA*> da_vec;
    construct(da_vec);
    for (auto& da : da_vec)
        func(*da);
}
英文:

I am the following structure. I minimized to the shortest possible way to reproduce the error:

I have two level of derived class. I don't have any compilation error. The error is at the runtime:

> Unhandled exception at 0x00007FFF1021CF19 in base.exe: Microsoft C++
> exception: std::__non_rtti_object at memory location
> 0x00000022B9BDF458.

Is there any suggection?

#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;memory&gt;

class Base {
public:
    int a;
    Base(int _a) : a(_a) {};
    virtual void print() = 0;
};

class derivedA : public Base
{
public:
    derivedA(int _a) : Base(_a) {};
    void print() { std::cout &lt;&lt; &quot;dA&quot; &lt;&lt; std::endl; }
};

class derivedB : public derivedA
{
public:
    derivedB(int _a) : derivedA(_a) {};
    void print() { std::cout &lt;&lt; &quot;dB&quot; &lt;&lt; std::endl; }
};

void construct(std::vector&lt;derivedA*&gt;&amp; da_vec) {
    da_vec.push_back(std::unique_ptr&lt;derivedA&gt;(new derivedB(4)).get());
}

void func(derivedA&amp; da)
{
    derivedB&amp; db = dynamic_cast&lt;derivedB&amp;&gt;(da);
    db.print();
}

int main()
{
    std::vector&lt;derivedA*&gt; da_vec;
    construct(da_vec);
    for (auto&amp; da : da_vec)
        func(*da);
}

答案1

得分: 5

Here is the translated code portion:

当你使用 push_back 存储 derivedB 基类指针时,你会存储一个悬挂指针。

da_vec.push_back(std::unique_ptr<derivedA>(new derivedB(4)).get());

unique_ptr<derivedA> 在表达式结束时被销毁,因此从 .get() 得到的指针是“悬挂”的,这意味着不应该对其进行解引用。它指向的对象已经不存在了。

为了解决这个问题,我建议你改为在你的 vector 中存储 std::unique_ptr<derivedA>。在调用覆盖的 print 方法之前,你也不需要强制转换为 derivedB&。这正是多态性为你自动解决的问题。

示例:

void construct(std::vector<std::unique_ptr<derivedA>>& da_vec) {
    da_vec.push_back(std::make_unique<derivedB>(4));
}

void func(derivedA& da) {
    //derivedB& db = dynamic_cast<derivedB&>(da);
    da.print();
}

int main() {
    std::vector<std::unique_ptr<derivedA>> da_vec;
    construct(da_vec);
    for (auto& da : da_vec)
        func(*da);
}

演示

注意:我还将 Base 析构函数标记为 virtual,这是必要的,以便通过基类指针销毁对象,以便调用 所有 析构函数(从最派生到基类)。

我还标记了覆盖的方法为 override,这并不是严格必需的,但在阅读代码时有所帮助 - 而且如果你 认为 你覆盖了某些东西,但实际上并没有,它还会在编译时引发错误。

英文:
  • When you push_back the derivedB base class pointer, you store a dangling pointer.
    da_vec.push_back(std::unique_ptr&lt;derivedA&gt;(new derivedB(4)).get());
    

    The unique_ptr&lt;derivedA&gt; is destroyed at the end of the expression, so the pointer you got from .get() is "dangling", which means that it should not be dereferenced. The object it pointed at is gone.

To solve that, I suggest that you instead store std::unique_ptr&lt;derivedA&gt; in your vector. You also do not need to cast to derivedB&amp; before calling the overridden print method. That's what polymorphism solves for you automatically.

Example:

void construct(std::vector&lt;std::unique_ptr&lt;derivedA&gt;&gt;&amp; da_vec) {
    da_vec.push_back(std::make_unique&lt;derivedB&gt;(4));
}

void func(derivedA&amp; da) {
    //derivedB&amp; db = dynamic_cast&lt;derivedB&amp;&gt;(da);
    da.print();
}

int main() {
    std::vector&lt;std::unique_ptr&lt;derivedA&gt;&gt; da_vec;
    construct(da_vec);
    for (auto&amp; da : da_vec)
        func(*da);
}

Demo

Note: I made the Base destructor virtual too which is necessary in order to destroy objects via a base class pointer in order for all the destructors to be called (from most derrived to the base).

I also marked the overridden methods with override which is not strictly necesssary, but helps when reading the code - and it will also give you a compilation error in case you think you override something, but actually isn't.

huangapple
  • 本文由 发表于 2023年5月25日 21:40:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/76332949.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定