首页 > 解决方案 > 有没有办法将 reinterpret_cast 重新解释为 virtual derived* 并从父级调用 override?

问题描述

#include <iostream>

template<typename T>
struct printer {

    virtual const T* get(size_t& sz) const = 0;

    void print() {
        size_t sz;
        const T* _t = get(sz); //tries to access 'this'
        for (size_t t = 0; t < sz; t++)
            std::cout << _t[t] << std::endl;
    }
};

template<typename T, size_t sz>
struct mask_t : public printer<T> {
    T data[sz];

    virtual const T* get(size_t& _sz) const override {
        _sz = sz;
        return data;
    }
};

int main(int argc, char** argv) {

    char* buffer = new char[1024];
    {
        using mask_f = mask_t<float, 12>;
        using mask_i = mask_t<int, 12>;

        mask_f* mf = reinterpret_cast<mask_f*>(buffer + 42);
        mask_i* mi = reinterpret_cast<mask_i*>(buffer + 42);

        //'this' is uninitialized
        mf->print();
        mi->print();

        mask_f _mf = *mf;
        mask_i _mi = *mi;

        //ok
        _mf.print();
        _mi.print();
    }
    delete[] buffer;

    return 0;
}

print()this调用时尝试访问get()是因为vfptr查找吗?换句话说,这不可能吗?

编辑:我知道我可以通过取消引用指针来创建一个新mask_t的,new或者像我在这里所做的那样。然后mask_t::this被定义。

我不想创建实例的原因是出于性能问题[这在我承认的示例中不可见]。如果您想回答,请解决本文中唯一的问题。

标签: c++reinterpret-castvirtual-inheritance

解决方案


无论类型如何,这都不是有效代码。在 C++ 中,您不能只是将随机指针投射到一个对象并假装它存在。

是的,在 C++20 中,它们确实允许您在某些情况下这样做。但即使在那里,这些情况也不包括对具有virtual成员函数的类型的操作(因为它们不够简单)。

只需使用placement-new来构造对象。这就是您应该如何在存储中创建对象的方式。


print() 在调用 get() 时尝试访问它是因为 vfptr 查找吗?

有关系吗?这是未定义行为如何导致崩溃的一个实现方面。

这:mask_f* mf = reinterpret_cast<mask_f*>(buffer + 42);导致未定义的行为。就像这样:mask_f _mf = *mf;。这两个都访问一个不存在的对象。因此,它们都表现出未定义的行为。

一个特定的编译器(版本)可能会使其中一个看起来像你想要的那样做并且可能使另一个崩溃是细节和实现的问题。这两段代码同样荒谬,都不能依赖它们来做你想做的事。

我可以解释为什么编译器生成的程序集允许您在一种情况下摆脱 UB 而在另一种情况下却不行。但这忽略了这样一个事实,无论哪种方式,您都依赖于 UB。

我正在读取远程进程的内存。

这在 C++ 中是不合理的。virtual无论如何,不​​适用于有成员的类型。传统的方法是将该类型的数据序列化到内存中,然后在接收过程中将其反序列化回该类型的新对象

现在是的,如果您愿意编写特定于平台的hackery,那么有一些方法可以在这样的进程之间传递virtual类型。它们需要提取 vtable 指针(从有效对象中)并将它们写入从远程进程接收到的对象数据中,从而有效地在原地“修复”对象。

但这些是特定于平台的黑客;如果你想要一些可移植的东西,你必须使用序列化。


推荐阅读