英文:
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 <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);
}
答案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
thederivedB
base class pointer, you store a dangling pointer.da_vec.push_back(std::unique_ptr<derivedA>(new derivedB(4)).get());
The
unique_ptr<derivedA>
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<derivedA>
in your vector
. You also do not need to cast to derivedB&
before calling the overridden print
method. That's what polymorphism solves for you automatically.
Example:
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);
}
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论