为什么类的reinterpret_cast <const char * =“”>及其预初始化成员Int是否相同而其他类型的变量不是?</const>

时间:2014-12-24 00:49:10

标签: c++ casting

我是通过在线考试(http://www.interqiew.com/tests?type=cpp)得到的,并且已经被困了一段时间。

我只是不明白。它编译并运行良好。我修改了代码以表达对古怪的更多表现。

CODE:

#include <cstddef>
#include <iostream>

class A{
public:
    A( ) : m_x( 3 ) { };
    static ptrdiff_t member_offsetA(const A &a){
        const char *p = reinterpret_cast<const char*>(&a);
        const char *q = reinterpret_cast<const char*>(&a.m_x);
        const char *z = reinterpret_cast<const char*>(&a.m_y);
        const char *s = reinterpret_cast<const char*>(&a.m_s);
        std::cout << q << " VS " << p << " VS " << z << " VS " << s << std::endl << std::endl;
        return p-q;
    }
    static ptrdiff_t member_offsetB(const A &a){
        const char *p = reinterpret_cast<const char*>(&a);
        const char *q = reinterpret_cast<const char*>(&a.m_x);
        const char *z = reinterpret_cast<const char*>(&a.m_y);
        const char *s = reinterpret_cast<const char*>(&a.m_s);
        std::cout << q << " VS " << p << " VS " << z << " VS " << s << std::endl << std::endl;
        return z-s;
    }
    static ptrdiff_t member_offsetC(const A &a){
        const char *p = reinterpret_cast<const char*>(&a);
        const char *q = reinterpret_cast<const char*>(&a.m_x);
        const char *z = reinterpret_cast<const char*>(&a.m_c);
        std::cout << q << " VS " << q << std::endl << " VS " << z << std::endl;
        return q-z;
    }
private:
    int m_x;
    int m_c;
    char m_y;
    std::string m_s;
};

int main(){
    A a;
    std::cout << ( ( A::member_offsetA( a ) == 0 ) ? 0 : 1 ) << std::endl;
    std::cout << ( ( A::member_offsetB( a ) == 0 ) ? 2 : 3 ) << std::endl;
    std::cout << ( ( A::member_offsetC( a ) == 0 ) ? 4 : 5 ) << std::endl;

    return 0;
}

输出:符号将由前面有三个X的唯一字母表示。因此,所有XXXS代表相同的符号。空白意味着没有打印出来。

XXXA VS XXXA VS   VS XXXB

0
XXXA VS XXXA VS   VS XXXB

3
XXXA VS XXXA
 VS XXXF
5

这有什么意义吗?

为什么类和成员int的转换会产生相同的结果?他们不会有所不同吗?如果它们相同,为什么其他成员的价值会有所不同?

另外,为什么有人会使用它?

P.S。粘贴实际输出:

 VS  VS �@ VS �����

0
 VS  VS �@ VS �����

3
 VS 
 VS �
5

1 个答案:

答案 0 :(得分:2)

我在这里看不到任何奇怪的事。这很有道理。

对于普通的非多态类,类实例的地址将与该类的第一个成员的地址相同。这就是一个类的实例;它是顺序排列的所有成员的总和(实例本身不添加任何内容,除非它是一个多态类,或者具有非空基类。)这是(不完全但几乎)在C ++中称为“标准布局”类(注意:实际定义显然更复杂。

对于类中的成员(实际上对于所有变量),其中没有两个可以具有相同的地址。事实上,他们需要1个或更多字节的内存(你知道,将它们各自的值的位存储在它们中。)因此,对于连续成员的地址不同,它再次完全合理。

您可能想查看此代码(我认为这更有启发性):

(注意:请注意我在这里使用指针算法时存在“未定义的行为”,所以这不完全正确的C ++。但据我所知,它工作正常。无论如何它都在这里用于演示目的,所以不要在生产中使用它!)

#include <cstddef>
#include <iostream>
#include <string>

template <typename T, typename U>
ptrdiff_t Dist (T const * from, U const * to) {
    return reinterpret_cast<char const *>(to) - reinterpret_cast<char const *>(from);
}

class A{
public:
    A( ) : m_x( 3 ) { };
    void printOffsetsAndSizes () const {
        std::cout << "A: " << reinterpret_cast<uintptr_t>(this) << " (" << sizeof(*this) << ")" << std::endl;
        std::cout << "  m_x: " << Dist(this, &m_x) << " (" << sizeof(m_x) << ")" << std::endl;
        std::cout << "  m_c: " << Dist(this, &m_c) << " (" << sizeof(m_c) << ")" << std::endl;
        std::cout << "  m_y: " << Dist(this, &m_y) << " (" << sizeof(m_y) << ")" << std::endl;
        std::cout << "  m_s: " << Dist(this, &m_s) << " (" << sizeof(m_s) << ")" << std::endl;
    }
private:
    int m_x;
    int m_c;
    char m_y;
    std::string m_s;
};

int main () {
    A a;
    a.printOffsetsAndSizes ();
    return 0;
}

在Ideone上提供此输出:

A: 3213332880 (16)
  m_x: 0 (4)
  m_c: 4 (4)
  m_y: 8 (1)
  m_s: 12 (4)