第一类将用于私有(private)继承,以确保完全相同的布局。这应该使类型转换安全。

#include <iostream>
#include <string>

struct data_base
{
    data_base( int i, std::string&& s ) noexcept
        : i_{ i }
        , s_{ std::move( s ) }
    {}

    int i_;
    std::string s_;
};

在这个简单的示例中,我首先打印int数据成员,然后打印std::string实例的data<true>数据成员。
template<bool = true>
struct data : private data_base // inherits
{
    data( int i, std::string&& s ) noexcept
        : data_base( i, std::move( s ) )
    {}

    void print()
    {
        std::cout << "data<true> - " << i_ << s_ << '\n';
    }
};

但是,data<false>首先打印std::string数据成员,然后再打印int数据成员。
template<>
struct data<false> : private data_base
{
    void print()
    {
        std::cout << "data<false> - " << s_ << i_ << '\n';
    }
};

例子:
int main()
{
    data<true> d{ 5, "abc" };
    d.print();
    ( ( data<false>& )d ).print();
}

演示:http://coliru.stacked-crooked.com/a/8b1262afe23dc0a2

如演示所示,即使打开-fstrict-aliasing标志,也没有警告。

现在,由于它们具有相同的布局,所以我认为可以在两种类型之间进行转换,以获得不同种类的静态多态性。无需调用虚拟函数。

这种用法安全吗?还是我触发了未定义的行为?

最佳答案

从语言规范的[expr.reinterpret.cast]/11中,您可以将引用从一种类型转换为另一种类型(如果可以将指向一种类型的指针转​​换为另一种类型)。

在您的类布局中,这两种类型都有一个通用的基类,该基类保存所有数据。这两个派生类型不添加任何数据成员,也不添加任何虚函数,因此两个类的对象布局将相同。

因此,如果您使用reinterpret_cast,则使用是安全的。

在这种情况下,这类似于将引用强制转换为基类,然后将该引用强制转换为另一个派生类。

关于c++ - 强制转换为具有相同数据成员布局但实现不同的类是否安全?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39381726/

10-11 15:00
查看更多