问题描述
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 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","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
ing from Bar to Bar 之后,虚函数指针仍然指向 Bar
我想知道这段代码是否定义良好,尤其是在“Foo”和“Wrapped Foo”的情况下。因此,只要我的函子中没有继承,我就可以将它重新解释为另一个 Foo,并且在调用 operator() 时,它将使用当前变量的模板类型的索引(分别为模板类型)调用它包装器被实例化)?
//编辑: 如果 Foo 构造函数被移除(并且 foo_ 成员被公开并从外部初始化),它看起来如何?
那么它应该构成一个 POD 并且标准 (9.2.18) 说明了 reinterpret_cast 和 POD:
一个指向 POD 结构对象的指针,适当地使用 reinterpret_cast,指向它的初始成员(或者如果该成员是一个 位域,然后到它所在的单元),反之亦然。 [ 注意:因此在 POD 结构中可能存在未命名的填充 对象,但不是在其开始时,因为需要实现适当的 对齐。
所以,如果 Foo 构造函数被移除,那么 Foo(和包装的 foo)的行为是否定义良好?
解决方法
Foo
的所有可能实例彼此无关,并且也与 Bar
的所有可能实例无关,它们同样彼此无关。 >
在无关类型之间使用 reintepret_cast
的行为是 undefined。
类看起来是否相同并不重要。例如,考虑
struct A{}; struct B{};
与
A a;
reinterpret_cast<B&>(a)
的行为也未定义。