我是通过在线考试(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
答案 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)