更新:我很感激“不想要那个,而是想要这个”的建议。它们非常有用,特别是在提供了激励场景的情况下。但是...无论好坏如何,我都变得好奇了,是否存在一种硬性的方法来实现“是的,在C++11中可以合法地做到这一点”与“不,不可能做到这样的事情”。
我想要将一个对象指针“别名”为另一种类型,唯一的目的是添加一些辅助方法。该别名不能向基础类添加数据成员(实际上,我能够防止发生这种情况就更好!)所有别名都适用于此类型的任何对象...只是如果类型系统能够提示哪个别名最合适,那就更好了。
关于任何特定别名的信息都不应该编码在基础对象中。因此,我觉得你应该能够“欺骗”类型系统,让它成为一个注释...在编译时进行检查,但最终与运行时转换无关。类似下面这样的东西:
Node<AccessorFoo>* fooPtr = Node<AccessorFoo>::createViaFactory();
Node<AccessorBar>* barPtr = reinterpret_cast< Node<AccessorBar>* >(fooPtr);
在幕后,工厂方法实际上制作了一个NodeBase类,然后使用类似的reinterpret_cast将其返回为Node *。为了避免这种情况,简单的方法是创建这些轻量级包装节点的类,并按值传递它们。因此,您不需要转换,只需要访问器类,在构造函数中获取节点句柄进行包装:
AccessorFoo foo (NodeBase::createViaFactory());
AccessorBar bar (foo.getNode());
但如果我不必为所有这些付费,我就不想要。例如,为每种封装指针类型(AccessorFooShared、AccessorFooUnique、AccessorFooWeak 等)制作特殊访问器类型。更喜欢将这些类型化指针别名为一个单一的基于指针的对象身份,并提供良好的正交性。
因此,回到最初的问题:
Node<AccessorFoo>* fooPtr = Node<AccessorFoo>::createViaFactory();
Node<AccessorBar>* barPtr = reinterpret_cast< Node<AccessorBar>* >(fooPtr);
似乎有一种可能有些丑陋但不会“违反规则”的方法来实现这个。根据ISO14882:2011(e) 5.2.10-7的说法:
深入到“标准布局类”的定义中,我们发现:对象指针可以显式转换为不同类型的对象指针。当类型为“指向T1的指针”的prvalue v被转换为类型“指向cv T2的指针”时,如果T1和T2都是标准布局类型(3.9),而T2的对齐要求不比T1更严格,或者其中一个类型是void,则结果为static_cast(static_cast(v))。将类型为“指向T1的指针”的prvalue转换为类型为“指向T2的指针”的prvalue(其中T1和T2是对象类型,并且T2的对齐要求不比T1更严格),然后再转换回其原始类型,将产生原始指针值。任何其他这样的指针转换的结果是未指定的。
- 没有非静态数据成员是非标准布局类(或这些类型的数组)或引用;
- 没有虚函数(10.3)和没有虚基类(10.1);
- 所有非静态数据成员的访问控制(第11条)相同;
- 没有非标准布局基类;
- 在最派生类中没有非静态数据成员,且至多有一个具有非静态数据成员的基类,或者没有具有非静态数据成员的基类;
- 没有与第一个非静态数据成员类型相同的基类。
std::is_standard_layout
来保持事情的检查。这能安全地完成吗?在gcc-4.7中似乎可以工作,但我想确保我没有调用未定义的行为。
Node<AccessorFoo>& foo = *new Node<AccessorFoo>;
。不过我还是不理解问题 :) - iammilind