这个包含reinterpret_cast模板类型之间的C++代码定义良好吗?
https://onlinegdb.com/RU3bYEfCB
#include <iostream>
using namespace std;
//--------------------Foo------------------
template<int Index>
class Foo {
public:
Foo(string first, string second, string third) {
foo_[0] = first;
foo_[1] = second;
foo_[2] = third;
}
string operator()() const {
return foo_[Index];
}
private:
string foo_[3];
};
//---------------------Bar------------------
class BarBase {
public:
virtual string operator()() const { return "BarBase"; };
};
template<int Index>
class Bar : public BarBase {
public:
Bar(string first, string second, string third) {
bar_[0] = first;
bar_[1] = second;
bar_[2] = third;
}
string operator()() const {
return bar_[Index];
}
private:
string bar_[3];
};
//---------------------Wrapper------------------
class WrapperBase {
public:
virtual string operator()() const { return "WrapperBase"; };
};
template<typename T>
class Wrapper : public WrapperBase {
public:
Wrapper(T* functor) : functor_(functor) {}
string operator()() const {
return (*functor_)();
}
private:
T* functor_;
};
int main()
{
Foo<0> foo0("A", "B", "C");
Foo<1>& foo1 = *reinterpret_cast<Foo<1>*>(&foo0);
Foo<2>& foo2 = *reinterpret_cast<Foo<2>*>(&foo0);
cout<< "foo: " << foo1() << foo2() <<"n";
Bar<0> bar0("A", "B", "C");
Bar<1>& bar1 = *reinterpret_cast<Bar<1>*>(&bar0);
Bar<2>& bar2 = *reinterpret_cast<Bar<2>*>(&bar0);
cout<< "bar: " << bar1() << bar2() <<"n";
WrapperBase* wrappedfoo0 = new Wrapper<Foo<0>>(&foo0);
WrapperBase* wrappedfoo1 = new Wrapper<Foo<1>>(&foo1);
WrapperBase* wrappedfoo2 = new Wrapper<Foo<2>>(&foo2);
cout<< "wrapped foo: " << (*wrappedfoo1)() << (*wrappedfoo2)() <<"n";
return 0;
}
输出:
foo: BC
bar: AA
wrapped foo: BC
Foo 和 Bar 完全等效,唯一的区别是 Bar 继承自基类并且实现的运算符是虚拟的,因此 Bar 有一个虚拟函数指针而 Foo 没有。
我想我明白为什么 bar 打印AA而 foo 打印BC(如果我错了,请纠正我)。这两个类都被实例化了 3 次,每个 operator() 有三个实现,各自的索引硬编码。但是,由于 Bar 有虚函数指针,所以在reinterpret_cast从 Bar<0> 到 Bar<1> 的 ing之后,虚函数指针仍然指向 Bar<0> 的实现
我想知道这段代码是否定义良好,尤其是在“Foo”和“Wrapped Foo”的情况下。因此,只要我的函子中没有继承,我就可以将它重新解释为另一个 Foo,并且在调用 operator() 时,它将使用当前变量的模板类型的索引(分别为模板类型)调用它包装器被实例化了)?
//编辑:
如果 Foo 构造函数被移除(并且 foo_ 成员被公开并从外部初始化),它看起来如何?
然后它应该构成一个 POD 并且标准 (9.2.18) 说明了 reinterpret_cast 和 POD:
使用 reinterpret_cast 适当转换的指向 POD 结构对象的指针指向其初始成员(或者如果该成员是位域,则指向它所在的单元),反之亦然。[注意:因此,POD-struct 对象中可能存在未命名的填充,但不是在其开头,这是实现适当对齐所必需的。
因此,如果删除了 Foo 构造函数,那么 Foo(和包装的 foo)的行为是否定义良好?
回答
的所有可能的实例化Foo彼此无关,并且也与 的所有可能的实例化Bar无关,它们也彼此无关。
reintepret_cast在无关类型之间使用的行为是undefined。
类看起来相同并不重要。例如,考虑
struct A{}; struct B{};
和
A a;
的行为reinterpret_cast<B&>(a)也是未定义的。
- @Caleth: Was what I meant, honest 😉