从多态容器中提取已知接口时的怪异行为
Weird behaviour when extracting a known interface from a polymorphic container
谁能帮我理解这种行为?简而言之:
- 我已经在一个公共容器中存储了多态对象。
- 其中一些实现了特定的接口。我能分辨出哪些是。 但是我不能使用这个接口。
下面是我总结的内容:
#include <iostream>
#include <vector>
// A base class
struct Base {
// A polymorphic method
virtual void describe() const {
std::cout << "Base" << std::endl;
};
virtual ~Base(){
std::cout << " Base destroyed" << std::endl;
};
};
// A specific interface
struct Interface {
virtual ~Interface(){
std::cout << " Interface Destroyed" << std::endl;
};
virtual void specific() = 0;
};
// A derived class..
struct Derived : public Base, public Interface {
virtual void describe() const {
std::cout << "Derived" << std::endl;
};
virtual void specific() {
std::cout << "Derived uses Interface" << std::endl;
};
virtual ~Derived() {
std::cout << " Derived destroyed" << std::endl;
};
};
int main() {
// Test polymorphism:
Base* b( new Base() );
Derived* d( new Derived() );
b->describe(); // "Base"
d->describe(); // "Derived"
// Ok.
// Test interface:
d->specific(); // "Derived uses Interface"
Interface* i(d);
i->specific(); // "Derived uses Interface"
// Ok.
// Here is the situation: I have a container filled with polymorphic `Base`s
std::vector<Base*> v {b, d};
// I know that this one implements the `Interface`
Interface* j((Interface*) v[1]);
j->specific(); // " Derived destroyed"
// " Interface destroyed"
// " Base destroyed"
// Why?! What did that object do to deserve this?
return EXIT_SUCCESS; // almost -_-
}
谁能告诉我我错过了什么?
有趣的事实:如果我交换Base::~Base
和Base::describe
的定义,那么对象描述自己而不是被销毁。为什么方法声明的顺序很重要?
这是避免c风格强制转换的一个很好的理由。当你这样做的时候:
Interface* j((Interface*) v[1]);
这是一个reinterpret_cast
。c风格的强制转换将尝试这样做,顺序是:const_cast
, static_cast
, static_cast
然后const_cast
, reinterpret_cast
, reinterpret_cast
然后const_cast
。在这种情况下,所有这些强制转换都是错误的!特别是reinterpret_cast
将只是未定义的行为,老实说,你为什么看到你看到的特定行为并不重要†。未定义行为是未定义的。
你要做的是:
Interface* j = dynamic_cast<Interface*>(v[1]);
这是通过运行时动态层次结构的正确转换,并将给您正确的 Interface*
对应于v[1]
(或nullptr
,如果v[1]
没有此运行时类型)。一旦我们解决了这个问题,那么j->specific()
打印Derived uses Interface
,正如你所期望的。
†这个问题很可能与虚值表对齐有关。当您执行重新解释强制转换时,由于
Base
没有specific
,因此该特定函数的偏移量可能与~Base()
对齐,因此效果是您直接调用析构函数—这就是为什么您看到了您所看到的。相关文章:
- 多态性和功能结合
- 具有默认模板参数的多态类的模板推导失败
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 多态二进制函数
- 访问存储在向量C++中的结构的多态成员
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- 将 std::allocate_shared 与多态资源分配器一起使用
- 通过switch和static_cast访问多态对象的运行时类型
- C++boost序列化多态性问题
- 如何模板化堆栈分配的多态指针数组到接口,包括派生类型的相应点?
- 为什么我在虚幻引擎中的多态性和接口方面遇到问题?
- 是具有接口专用化的子类多态的模板实例化
- 为什么在将多态行为与指向接口的指针一起使用时没有调用析构函数?
- 多态值类型和接口
- C++接口、继承、多态性
- 从接口派生的模板 - 多态性停止工作
- 如何通过多态基类接口使用模板化的子类
- 带有模板接口的C++多态性
- 从多态容器中提取已知接口时的怪异行为
- c++多态接口