I was given this code to test my cpp understanding, and I am quite confused:
#include "stdafx.h"
#include <iostream>
#include <cstddef>
using namespace std;
class A
{
public:
A() : m_x(0) { }
public:
static ptrdiff_t member_offset(const A &a)
{
const char *p = reinterpret_cast<const char*>(&a);
const char *q = reinterpret_cast<const char*>(&a.m_x);
return q - p;
}
private:
int m_x;
};
class B
: public A
{
public:
B() : m_x('a') { }
public:
static int m_n;
public:
static ptrdiff_t member_offset(const B &b)
{
const char *p = reinterpret_cast<const char*>(&b);
const char *q = reinterpret_cast<const char*>(&b.m_x);
return q - p;
}
private:
char m_x;
};
int B::m_n = 1;
class C
{
public:
C() : m_x(0) { }
virtual ~C() { }
public:
static ptrdiff_t member_offset(const C &c)
{
const char *p = reinterpret_cast<const char*>(&c);
const char *q = reinterpret_cast<const char*>(&c.m_x);
return q - p;
}
private:
int m_x;
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
B b;
C c;
std::cout << ((A::member_offset(a) == 0) ? 0 : 1);
std::cout << ((B::member_offset(b) == 0) ? 0 : 2);
std::cout << ((A::member_offset(b) == 0) ? 0 : 3);
std::cout << ((C::member_offset(c) == 0) ? 0 : 4);
std::cout << std::endl;
return 0;
}
The answer is 0204.
I have understand the first 3cases, but not the last one. The difference between the last and first is a virtual desctructor. Is this related? If yes, how?
The code example has an implementation defined behavior. The output for any of the cases cannot be guaranteed. It is not guaranteed that members of a class are always placed in contiguous memory locations.There can be padding bytes added in between them. And whether or not padding is added is left out as an implementation detail. Your suspicion of
virtualplaying a role just might be true[Note 1:]. But the important thing to note is even without thevirtualthe output is not guaranteed.Reference:
C++11: 9.2 Class members [class.mem]
[Note 1]:
Dynamic dispatch itself is a implementation defined mechanism but most(read all known) implementations use the virtual table and pointer mechanism to implement it.
In case of a polymorphic class(which does not derive from any other class) usually the virtual pointer is stored as the first element of class. So it is reasonable to assume that this is what happens behind the scenes in the last case when you run the code sample on your environment.
Online sample:
Output: