Questions about C class summary (a) Author: Jiang Jiang QQ: 457283E-mail: jznsmail@163.net
I have encountered many problems in the process of learning C , especially for class. Therefore, by doing some experiments, I summed it, it is a summary of my own learning, and I also want to give a person who is confused by these issues. If there are some wrong places in the article, or you have your own opinion, welcome to criticize the pointer. I hope we can make progress together.
1. The size of the empty class, for example: Class A {}; how much is the size of class A? Is equal to 0? Below we will explain the problem through a test, the procedure is as follows: #include
Using namespace std;
Class a {};
INT main () {a a; cout << "Size of a is =" << SizeOf (a) << endl; cout << "address of a is =" << & a << endl; return 0;}
The output of the program on my computer is: size of a is = 1 address of a is = 0012ff7c See this result is dumbful? Equal to 1? How will any member variables are equal to 1? That's right, you didn't read the wrong, it is indeed 1. Because it is dark to generate 1byte, it is done for us to identify two different classes of this class in memory. Think about it, if you don't have this 1byte, allocate two class A, so how to identify?
2. The size of the class containing the member variables We still explain the problem with the procedure, the procedure is as follows: #include
Using namespace std;
Class a {public: int m_test1; int m_test2;};
INT main () {a a; cout << "Size of a is =" << SizeOf (a) << endl; cout << "address of a is =" << & a << endl; return 0;}
The result of the program output on my computer is: size of a is = 8 Address of a is = 0012ff78 At first glance, everyone will understand that because the next int type of Win32 occupies 4Byte, then 2 will be equally equal to 8 Oh, it's right, but don't be happy too early, let's see this procedure: #include
Using namespace std;
Class a {public: int m_test1; int m_test2; char m_trick [1]; // joined this line code};
INT main () {a a; cout << "Size of a is =" << SizeOf (a) << endl; cout << "address of a is =" << & a << endl; return 0;}
The result of the program output on my computer is: size of a is = 12 address of a is = 0012ff74 Why is the result of the program output is 12 instead of our expected 9 (int int char = 9byte)? This is because there is a molbization principle, that is, adjust the numerical value to an integer multiple of a number of digits. This number is 4 in 32, which makes the BUS's transmission is the fastest. So we define a Char array containing an element being aligned to occupy 4 bytes, so a total of 4 4 4 = 12.
3. The situation inheritance inherits a class, then how is the members variable of the party to arrange? Let's take a look at the code: #include
Using namespace std;
Class a {public: int m_test1; int m_test2; char m_trick [1]; // Add this line of code, in order to generate memory, so good observation. }
Class B: PUBLIC A {public: int m_test3; void printaddress () {cout << "address of b :: m_test1 is =" << & m_test1 << endl; cout << "address of b :: m_test2 is =" < <& m_test2 << endl; cout << "address of b :: m_test3 is =" << & m_test3 << endl; cout << "address of b :: m_trick is =" << & m_trick << endl;}};
INT main () {a a; cout << "Size of a is =" << SizeOf (a) << endl; cout << "address of a is =" << & a << endl;
B b; cout << "size of b is =" << sizeof (b) << endl; cout << "address of b is =" << & b << endl;
Cout << "The Member of B Address IS:" << endl; b.printaddress ();
Return 0;}
The output result of the program on my computer is: size of a is = 12 address of a is = 0012ff74 size of b IS = 16 address of b IS = 0012FF64 The Member of B Address IS: address of b :: m_test1 is = 0012ff64 address of b :: m_test2 is = 0012ff68 address of b :: m_test3 is = 0012ff70 address of b :: m_trick is = 0012ff6c pay attention to this result, m_test1, m_test2, m_trick is inherited from class A, m_test3 is derived class The member variable, because if the member variable in the derive class is the base class, the address of M_Test3 should be 0012FF6D without 0012ff70, so it is understood that the member variable of the derived class is not immediately defined back to the base class member variable, Why is the address of M_Test3 is 0012FF70 because there is 3 bytes of memory alignment behind M_trick. 4. Class inheritance containing virtual functions If the class contains a virtual member function, what is the structure of the memory? Let's take a look at the analysis program: #include
Using namespace std;
Class a {public: virtual void fun () {cout << "A :: fun" << endl;}};
INT main () {a a; cout << "Size of a is =" << sizeof (a) << endl; cout << "address of a is = << & a << endl; return 0;} What is the size of class A? Maybe you will say it is 0 because no member variables are defined. Well, wrong, let's take a look. The result of output on my computer is: size of a is = 4 address of a is = 0012ff7c Why is 4 instead of 0, it is because the virtual function is pointing to a VTBL through a VPTR (virtual function pointer) pointer (Virtual function table) to complete the function call. When you have a class object, the compiler has done some work, which is to establish a VPTR and a VTBL, store the function address into the VTBL, and then use the VPTR pointer established by the compiler to point to VTBL. Maybe you will also doubt this result, think it is not a saved culprit pointer instead of a virtual function pointer? Well, let's take a look at the case of multiple virtual functions. Pace STD;
Class a {public: Virtual void fun1 () {cout << "A :: fun1" << endl;} Virtual void fun2 () {cout << "A :: fun2" << Endl; {cout << "A :: fun3" << endl;}};
INT main () {a a; cout << "size of a is =" << SizeOf (a) << endl; cout << "address of a is =" << & a << Endl; return 0;} The result of the output on my computer is: size of a is = 4 address of a is = 0012ff7c
Well, the result is still 4, just as I said above, the compiler automatically joined us a VPTR pointer, pointing to a VTBL, by this vtbl to maintain the virtual function. You may also ask if there is a virtual function table (VPTR), then it is there? How is VPTR and member variables in memory? My code is as follows: #include
Using namespace std;
Class a {public: int m_test1; int m_test2; a (const INT x = 0, const y = 0): m_test1 (x), m_test2 (y) {} int GetTest1 () const {return m_test1;} int Gettest2 ) const {return m_test2;} Virtual void fun () {}};
INT main () {a a (10, 20);
INT * PINT = (int *) & a; * (PINT 0) = 100; * (PINT 1) = 200; cout << "test1 =" << a.gettest1 () << Endl; cout << " TEST2 = "<< a.gettest2 () << endl; return 0;} If you don't see the result, you will not be Lima, the output should be 100,200. I seem to have a little problem, don't believe it? Let's take a look at my output:
TEST1 = 200 TEST2 = 20
Oh, it's really not starting to guess, why? What is wrong? Remember what I mentioned above? Any VPTR is automatically generated for the virtual function compiler? The first location of the incapable member function is stored this VPTR. So it will cause this result. If we make a little modification, as follows:
#include
Using namespace std;
Class a {public: int m_test1; int m_test2; a (const INT x = 0, const y = 0): m_test1 (x), m_test2 (y) {} int GetTest1 () const {return m_test1;} int Gettest2 ) const {return m_test2;}};
INT main () {a a (10, 20);
INT * PINT = (int *) & a; * (pint 0) = 100; // pay attention to this line! * (Pint 1) = 200; // Note this line Cout << "TEST1 =" << a.gettest1 () << endl; cout << "test2 = << a.gettest2 () << Endl; Return 0;} The result of the output on my computer is: test1 = 100 test2 = 200
When I have modified offset, the output result is correct, and a VPTR is placed at the first location of the member function.
5. In-depth understanding of the virtual function we mentioned VPTR and VTBL, then let us take a look at these two allocations: 4 # include
Using namespace std;
Class A {Virtual Fun () {cout << "A :: fun" << endl;}};
INT main () {a a; cout << "Address of Virtual Pointer is =" << (int *) (& A 0) << Endl; cout << "Value At Virtual Pointer IS = << (int *) ) * (int *) (& A 0) << endl; return 0;}
The result is: address of virtual pointer is = 0012FF7C Value At Virtual Pointer IS = 0046c06c
I used two tips to get the address of the virtual function pointer, and the address of the virtual function table. (INT *) (& A 0) First take the address, then add 0 offset, why add 0 because of the first position of the VPTR in the member function in 4 o'clock. (Int *) * (int *) (& A 0) First get the contents of the pointer of the virtual function table, and then ask the address so that the address of the VTBL is obtained.
Since this, let us call a virtual function through this trick :) #include
Using namespace std;
TypeDef void (* fun) (VOID);
Class A {Virtual Void Fun () {cout << "A :: fun" << endl;}};
INT main () {a a; cout << "Address of Virtual Pointer is =" << (int *) (& A 0) << Endl; cout << "value at vritual pointer is = << (int * ) * (int *) (& A 0) << endl; cout << "Value at first entry of var * (int *) * (int *) (INT *) (& A 0) << Endl; cout << endl << "executing vritual funciton" << Endl << Endl; Fun PFUN = (fun) * (int *) * (INT *) (& A 0); PFUN (); RETURN 0 } The output result in my computer is:
Address of Virtual Pointer IS = 0012FF7C Value At Vritual Pointer IS = 0046C0C0 Value At First Entries Of Virtual Table IS = 0040128F
Executing Vritual Funciton
A :: fun
Well, call the virtual function, the fruit is really through VPTR to point VTBL, and VTBL saves the address of the virtual function. The problem is coming again, how is the virtual function arranged in memory? How is it to determine the length of the virtual function table? The answer is null, we will take a look at: #include
Using namespace std;
TypeDef void (* fun) (VOID);
Class A {Virtual Void Fun () {cout << "A :: Fun" << Endl;} Virtual Void Fun1 () {cout << "A :: Fun1" << endl;}};
INT main () {a a; cout << "Address of Virtual Pointer is =" << (int *) (& A 0) << Endl; cout << "value at vritual pointer is = << (int * ) * (int *) (& A 0) << endl; cout << "Value at first entry of var * (int *) * (int *) (INT *) (& A 0) << endl; cout << "Value at 2nd entry of var-" value is = "<< (int *) * ((int *) * (int *) 1) << Endl; cout << "Value at 3rd Entry of Virtual Table IS =" << (INT *) * (INT *) * (INT *) 2) << endl; cout << "Value At 4th Entry of Virtual Table IS = "<< (int *) * (INT *) * (INT *) 3) << Endl; cout << endl <<" Executing Vritual Funciton << Endl << Endl Fun pfun = (fun) * (int *) * (int *) (& A 0); pfun (); return 0;}
The output of the output on my computer is:
Address of virtual pointer is = 0012FF7C Value at vritual pointer is = 0046C15C Value at first entry of virtual table is = 00401294 Value at 2nd entry of virtual table is = 004010DC Value at 3rd entry of virtual table is = 00000000 Value at 4th entry of virtual Table is = 663a3a41
Because we define two virtual functions, when output to the address of the third virtual function, the output is 0 so that we can know that it is indeed that I just said, the function table will determine its length through null. I will give it in subsequent articles about multiple layers. (to be continued...)