visual c ++
In our object-oriented world the class is a minimal unit, a brick for constructing our applications. It is an abstraction and we know well how to use it. In well-designed software we are not usually interested in knowing how objects look in memory.
在我们面向对象的世界中,类是一个最小的单元,是构建我们的应用程序的一块砖。 这是一个抽象,我们很清楚如何使用它。 在设计良好的软件中,我们通常对了解对象在内存中的外观通常不感兴趣。
Sometimes the understanding of the memory structure of the C++ class may help in the modern design.
有时,对C ++类的内存结构的理解可能有助于现代设计。
I have to mention that I work with Microsoft Visual Studio and all code posted here was written for this compiler. More then it, I guess that the object memory layout can be different from the one I'm showing here, if you use another compilers. Some "tricks" you will see here are dangerous enough to be used in the production code. It is good to know, nice to understand, but to use such tricks in the real projects... from my point of view it smells very bad.
我不得不提到我使用Microsoft Visual Studio,并且这里发布的所有代码都是为此编译器编写的。 而且,如果您使用其他编译器,我想对象内存布局可能与我在此处显示的布局有所不同。 您将在此处看到的一些“技巧”足够危险,无法在生产代码中使用。 很高兴知道,也很高兴理解,但是在实际项目中使用这样的技巧……从我的角度来看,它很难闻。
The following application shows the size of few a trivial objects:
以下应用程序显示了一些琐碎的对象的大小:
#include <Windows.h>
#include <stdio.h>
class CEmpty
{
};
class C1Int
{
int x;
};
class C2Int
{
int x;
int y;
};
class C3Int
{
int x, y, z;
};
class CInt
{
int x;
public:
CInt() : x(0) {}
};
class CIntDerived: public CInt
{
int y;
public:
CIntDerived() : y (0) {}
};
class CCharArray
{
char x[24];
};
class CStr
{
char x[24];
public:
CStr()
{
strcpy(x, "Hello");
}
};
int main()
{
CEmpty empty;
C1Int one;
C2Int two;
C3Int three;
CInt simple;
CIntDerived derived;
CCharArray charArray;
CStr str;
printf("Size of CEmpty object is %d\r\n", sizeof(empty));
printf("Size of C1Int object is %d\r\n", sizeof(one));
printf("Size of C2Int object is %d\r\n", sizeof(two));
printf("Size of C3Int object is %d\r\n", sizeof(three));
printf("Size of CInt object is %d\r\n", sizeof(simple));
printf("Size of CIntDerived object is %d\r\n", sizeof(derived));
printf("Size of CCharArray object is %d\r\n", sizeof(charArray));
printf("Size of CStr object is %d\r\n", sizeof(str));
return 0;
}
Object of the class with only one integer as a member has size 4 bytes. Objects with 2 or 3 integers inside use 8 and 12 bytes accordingly. (Size of the integer type is platform/compiler specific and will vary on diffrent platforms and compilers because the standard does not specify the size of any integral type)
只有一个整数作为成员的类对象的大小为4个字节。 内部带有2或3个整数的对象分别使用8和12个字节。 (整数类型的大小是特定于平台/编译器的,并且在不同的平台和编译器上会有所不同,因为该标准未指定任何整数类型的大小)
The last declared class with an array as the member-variable has the same size as the array. The class methods do not change the size.
最后声明的带有数组作为成员变量的类具有与数组相同的大小。 类方法不会更改大小。
All shown classes have only private members, but all these members can be printed out:
所有显示的班级只有私人成员,但是所有这些成员都可以打印出来:
#include <Windows.h>
#include <stdio.h>
class C1Int
{
int x;
public:
C1Int() : x(0) {}
};
class C2Int
{
int x;
int y;
public:
C2Int() : x(1234), y(5678) {};
};
class CStr
{
char x[24];
public:
CStr()
{
strcpy(x, "Hello");
}
};
int main()
{
C1Int one;
C2Int two;
CStr str;
printf("C1Int::x = %d\r\n", *(int*)&one);
printf("C2Int::x = %d\r\n", *(int*)&two);
printf("C2Int::y = %d\r\n", *((int*)&two + 1));
printf("CStr::x = %s\r\n", (char*)&str);
return 0;
}
#include <Windows.h>
#include <stdio.h>
class CInts
{
int x;
int y;
public:
CInts() : x(1234), y(5678) {};
void out()
{
printf("CInts::x = %d\r\n", x);
printf("CInts::y = %d\r\n", y);
}
};
int main()
{
CInts one;
one.out();
//the following 2 lines are very dangerous and may cause a crash if you'll
//try to use this style in your projects
*(int*)&one = 111;
*(((int*)&one) + 1) = 222;
one.out();
return 0;
}
struct ints { int x; int y; }
#include <Windows.h>
#include <stdio.h>
class CStr
{
char text[32];
public:
CStr(char* psz)
{
text[0] = 0;
if (psz != NULL)
strncpy(text, psz, 30);
};
};
int main()
{
CStr str("Hello");
printf("str = %s\r\n", &str);
strcpy((char*)(&str), "bye");
printf("str = %s\r\n", &str);
return 0;
}
The following application shows that even the class that has nothing but only one virtual method takes 4 bytes in the memory.
以下应用程序显示,即使只有一个虚拟方法的类也只占用4个字节的内存。
#include <Windows.h>
#include <stdio.h>
class CEmpty
{
public:
virtual void out()
{
printf("CEmpty\r\n");
}
};
class C1Int
{
int x;
public:
C1Int() : x(0) {}
virtual void out_x()
{
printf("x = %d\r\n", x);
}
};
class C2Int
{
int x, y;
public:
C2Int() : x(0), y(0) {}
virtual void out_x()
{
printf("x = %d\r\n", x);
}
virtual void out_y()
{
printf("y = %d\r\n", y);
}
};
class CIntDerived: public C1Int
{
int y;
public:
CIntDerived() : y (0) {}
virtual void out_y()
{
printf("y = %d\r\n", y);
}
};
int main()
{
CEmpty empty;
C1Int one;
C2Int two;
CIntDerived derived;
printf("Size of CEmpty object is %d\r\n", sizeof(empty));
printf("Size of C1Int object is %d\r\n", sizeof(one));
printf("Size of C2Int object is %d\r\n", sizeof(two));
printf("Size of CIntDerived object is %d\r\n", sizeof(derived));
return 0;
}
Let's investigate it in the debug mode. Stop the debugging of the following application and check the object in the memory window (type &str in the edit box there), we will find these 4 bytes - "Hello" is not in the beginning of the object memory. It moved for 4 bytes. And the first 4 bytes are the pointer that we didn't see in the previous examples. It can be only a pointer to the virtual method table.
让我们在调试模式下进行研究。 停止以下应用程序的调试,并在内存窗口中检查对象(在此处的编辑框中键入&str),我们将发现这4个字节-“ Hello”不在对象内存的开头。 它移动了4个字节。 前4个字节是我们在前面的示例中未看到的指针。 它只能是指向虚拟方法表的指针。
#include <Windows.h>
#include <stdio.h>
class CStr
{
char text[32];
public:
CStr(char* psz)
{
text[0] = 0;
if (psz != NULL)
strncpy(text, psz, 30);
}
virtual void out()
{
printf("text = %s\r\n", text);
}
};
int main()
{
CStr str("Hello");
str.out();
return 0;
}
#include <stdio.h>
class C1Int
{
int x;
public:
virtual void test()
{
printf("C1Int::test()\r\n");
}
};
class C2Int : public C1Int
{
int y;
public:
virtual void test()
{
printf("C2Int::test()\r\n");
}
virtual void test1()
{
printf("C2Int::test1()\r\n");
}
virtual void test2()
{
printf("C2Int::test2()\r\n");
}
};
int main()
{
C2Int two_int;
printf("size of C2Int object is %d\r\n", sizeof(two_int));
printf("Address of C2Int object is %p\r\n", &two_int);
int* p = (int*)(&two_int);
printf("Address of C2Int pointer is %p\r\n", p);
int p1 = *((int*)(&two_int));
printf("Value of this pointer is %x\r\n", p1);
int* _p1 = (int*)*((int*)(&two_int));
printf("Same.. pointer is %p\r\n", _p1);
int* p2_1 = (int*)*((int*)*(int*)(&two_int));
printf("Value of first entry of C2Int VTable is %p\r\n", p2_1);
int* p2_2 = (int*)*((int*)*(int*)(&two_int) + 1);
printf("Value of second entry of C2Int VTable is %p\r\n", p2_2);
int* p2_3 = (int*)*((int*)*(int*)(&two_int) + 2);
printf("Value of third entry of C2Int VTable is %p\r\n", p2_3);
int* p2_4 = (int*)*((int*)*(int*)(&two_int) + 3);
printf("Value of fourth entry of C2Int VTable is %p\r\n", p2_4);
int* p2_5 = (int*)*((int*)*(int*)(&two_int) + 3);
printf("Value of fifth entry of C2Int VTable is %p\r\n", p2_5);
return 0;
}
#include <stdio.h>
class C1Int
{
public:
virtual void test()
{
printf("C1Int::test()\r\n");
}
};
class C2Int : public C1Int
{
public:
virtual void test()
{
printf("C2Int::test()\r\n");
}
virtual void test1()
{
printf("C2Int::test1()\r\n");
}
virtual void test2()
{
printf("C2Int::test2()\r\n");
}
};
typedef void (* func)();
int main()
{
C2Int two_int;
int* p = (int*)(&two_int);
printf("Address of C2Int pointer is %p\r\n", p);
int p1 = *((int*)(&two_int));
printf("Value of this pointer is %x\r\n", p1);
int* p2_1 = (int*)*((int*)*(int*)(&two_int));
printf("Value of first entry of C2Int VTable is %p\r\n", p2_1);
int* p2_2 = (int*)*((int*)*(int*)(&two_int) + 1);
printf("Value of second entry of C2Int VTable is %p\r\n", p2_2);
int* p2_3 = (int*)*((int*)*(int*)(&two_int) + 2);
printf("Value of third entry of C2Int VTable is %p\r\n", p2_3);
func f1 = (func)p2_1;
f1();
f1 = (func)p2_2;
f1();
f1 = (func)p2_3;
f1();
C1Int one_int;
func f2 = (func)((int*)*((int*)*(int*)(&one_int)));
f2();
return 0;
}
#include <stdio.h>
#include <memory>
class CBase
{
public:
virtual void test()
{
printf("CBase::test()\r\n");
}
};
class CVirtTest
{
public:
virtual void test()
{
printf("CVirtTest::test()\r\n");
}
};
typedef void (* func)();
typedef struct
{
func Entry;
} FUNC_TABLE;
void Trick()
{
printf("Trick()\r\n");
}
int main()
{
CVirtTest test;
CBase* pBase = (CBase*)&test;
FUNC_TABLE funcTable = { Trick };
FUNC_TABLE* pFuncTable = &funcTable;
//dangerous code, don't use it in your projects.
memcpy(&test, &pFuncTable, sizeof(long));
pBase->test();
return 0;
}
I think the following pseudocode illustrates everyhting I was talking about:
我认为以下伪代码说明了我所谈论的一切:
An object of the class declared as:
该类的对象声明为:
class ClassStructure
{
int x;
int y;
public:
virtual void nothing() {};
}
struct ClassStructure
{
void* m_pVptr;
int x;
int y;
}
Wikipedia: C++ classes.
维基百科:C ++类。
Memory Layout for Multiple and Virtual Inheritance.
多重和虚拟继承的内存布局。
or in this book:
或在这本书中:
Steve Oualline. Practical C++ Programming, Second Edition.
史蒂夫·夸林(Steve Oualline)。 实用C ++编程,第二版。
翻译自: https://www.experts-exchange.com/articles/1242/Visual-C-Object-Memory-Layout.html
visual c ++