在下面的代码中:
#include <iostream>
#include <thread>
#include <mutex>
#include <functional>
struct IView {
virtual void setOnClick() = 0;
};
struct ITextView : IView {
virtual void setText() = 0;
};
struct IButton : ITextView {
virtual void setRadius() = 0;
};
struct View : IView {
int i = 1;
virtual void setOnClick() override {
std::cout << "setting OnClick! i: " << i << std::endl;
};
};
/// Works as is
/// But if make "TextView : View, ITextView" - have segfault on the run
struct TextView : ITextView, View {
int j = 2;
virtual void setText() override {
std::cout << "setting text! i: " << i << " j: " << j << std::endl;
};
// forward IView
virtual void setOnClick() override {
View::setOnClick();
}
};
int main() {
TextView tv;
void* ptr = &tv; // I need to pass raw pointer, and then restore "interface" from it
ITextView* itv = static_cast<ITextView*>(ptr); // I don't need safety checks here
itv->setOnClick();
itv->setText();
return 0;
}
如果我更改 TextView
的继承顺序,我将在 itv->setText();
调用上出现段错误。
为什么重要?我可以在这里使用static_cast
,还是我这里有UB?据我了解,dynamic_cast
只需要虚拟继承,而据我所知,情况并非如此。
最佳答案
就目前而言,您从 TextView*
隐式转换为 void*
,然后从 void*
显式转换为 ITextView*
。这些转换在从/向 void*
转换时不执行任何指针调整,因此您最终得到一个类型为 ITextView*
的指针,它实际上指向一个 TextView
(不是它的 ITextView
子对象!):随之而来的是未定义的行为。
解决方案是始终在void*
的“两侧”使用完全相同的类型:
TextView tv;
void* ptr = static_cast<ITextView*>(&tv); // Adjust, then convert to void*
ITextView* itv = static_cast<ITextView*>(ptr);
关于C++多接口(interface)继承和static_cast,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47331823/