[C + +] class, object memory layout, declaration and implementation separation

class

Use struct and class to define a class

In C language, struct is a structure and cannot write functions into it

In C + +, struct is a class into which functions can be written

  • Creating objects with classes

    struct Person {  
        int age;    
        void run() {  
            cout << "Person::run - " << age << endl; 
        }
    }
    int main() {  
        Person person; 
        person.age = 10; 
        person.run();  
        Person *p = &person; 
        // Use a pointer to an object  
        p->age = 20; 
        // Accessing objects using pointers
        p->run();     
        getchar();   
        return 0;
    }
    

    The memory of the person object and p pointer in the above code are automatically allocated and reclaimed in the stack space of the function.

    • The memory occupied by the class is only the variable size defined in the class. For example, there is only one int age variable in the above Person class, and the Person class only occupies 4 bytes.

      Q: do the functions in the class not occupy the address size?

      No, because the same class does not need to repeatedly open up the space of the same function, just call the same function. However, variables cannot be called each other, so variables need to open up a new space to store each time the class is called.

    • The difference between class and struct (only this one)

      • The default member permission of struct is public: it can be accessed directly

        The default member permission of class is private: it cannot be accessed directly


    Attention should be paid to naming conventions:

    • Global variable: g_
    • Member variable: m_
    • Static variable: s_
    • Constant: c_
  • Object's memory layout

    • Q: if there are multiple member variables in the class, how is the memory of the object arranged?

      such as

      struct Person {  
          int m_id;   
          int m_age; 
          int m_height;     
          void display() {     
              cout << "m_id - " << m_id << endl; 
          }
      }
      

      The memory addresses of the three variables defined in Person are continuous

      If defined

      Person person;
      person.m_id = 1;
      person.m_age = 2;
      person.m_height = 3;
      

      Memory address:

      In the order in which classes are defined.

      Note: the address value of the first variable in person is the address value of person.

    • Object memory for object-oriented creation is created in the heap

      But there is stack space in the person object

      If the object is defined outside the main function, it is a global variable, and the memory occupied is in the global area (data segment)

    • Layout of memory space:

      Person person1;
      Person person2;
      person1.m_id = 1;
      person2.m_id = 2;
      person1.run();
      person2.run();
      
      • Q: the run addresses called by person1 and person2 are the same. How does the system distinguish them when running?

        If the address of the parameter is given when calling the function, the function can easily find the value of the parameter in the stack space and call.

        struct Person { 
            int m_age;     
            void run(Person *person) {
                cout << "Person age - " << person->m_age << endl;  
            }   
            void run() {   
                // this = &person;   
                cout << "Person age - " << m_age << endl;  
                // cout << "Person age - " << this->m_age << endl;  
            }
        }
        

        This allows you to explicitly specify the address of the incoming parameter.

        But in fact, it is not written like this, but like the second method.

        Because the compiler automatically adds an implicit pointer this to the function in the class, it will automatically pass in the address value of the function caller and point to the function caller.


        (here, the address value of person1 is passed to ecx

        Plus this assembly code is the same.

        If this is called by Person1, the address value of Person1 will be passed in; Person 2 is a truth.

      The function is stored in the code area in the form of machine code, but when calling the function, additional storage space needs to be allocated to store the local variables inside the function.

      (the run function is stored in the code area, but when running this function, a space will be allocated in the stack space to store the function variables

      • Q: how to use pointers to indirectly access the member variables of the pointed object?

        1. Takes the address of the object from the pointer

        2. Use the address of the object + the offset of the member variable to calculate the address of the member variable

        3. Access the storage space of the member variable according to the address of the member variable

          Person *p = &person;
          p->m_id = 10;
          p->m_age = 10;
          p->m.height = 10;
          p->display();
          

          [ebp-14h] - address of person

          [ebp-20h] - address of pointer variable p

          If you directly modify the members in the object without pointers, for example

          Person p;
          p.m_id = 10;
          p.m_age = 10;
          p.m.height = 10;
          p.display();
          

          Then the assembly code is only mov [address], 0Ah

          **Question: * * if you use pointers to modify the values of members indirectly, two lines of code are required for assembly and only one line is required for direct modification. Is the efficiency of using pointers lower than that of direct modification?

          It is right in terms of the number of assembly instructions.

          However, there is no need to pay attention to the efficiency here, because in some cases, pointers must be used instead of direct modification. For example, heap space can only be accessed through addresses, and pointers can only be used when only addresses are passed in.

          Thinking questions:

          Person person;
          person.m_id = 10;
          person.m_age = 20;
          person.m_height = 30;
          Person *p = (Person *) &person.m_age;
          p->m_id = 40;
          p->m_age = 50;person.display();
          

          Q: person display(); What is the print?

          According to the previous assembly that uses pointers to indirectly modify member values:

          lea eax, [ebp-14h] 			
          // First take out the address of the referenced member and pass it into eax		
          // But M is passed in_ Age's address	
          mov dword ptr [ebp-20h],eax		
          // Assign the stored address in eax to the pointer variable     
          mov eax,dword ptr [ebp-20h]		
          // The last three paragraphs assign values to the three members according to the offset of eax
          mov dword ptr [eax] ,0Ah	
          // The address of eax in this place is the address of person, that is, the address of the first member     	
          // But in the above thinking code, M is passed to eax_ Age's address, eax+4
          mov eax,dword ptr [ebp-20h]	
          // Therefore, the values of eax+4 and eax+8 are modified, i.e. m_age and M_ Value of height
          mov dword ptr [eax+4],0Ah	
          // So the final output is 10, 40, 50   
          mov eax,dword ptr [ebp-20h]
          mov dword ptr [eax+8], eAh
          mov ecx, dword ptr [ebp-20h]
          

          Person *p = (Person *) &person.m_age; This place must strengthen the transfer (person *), because person m_ Age is an int type. You cannot assign an int type to person *

          **Q: * * if person How about replacing display() with P - > display()?

          40, 50, cross the border

          P - > display() will pass the address stored in pointer p to this of the display function, that is & person m_ age

        Q: why is it all cc?

        When calling the function to allocate the stack space, the stack space may have been used by other functions before, so there is still garbage data in it. Therefore, before the next use, fill the space with cc, which is equivalent to emptying the data.

        Then why not fill in 0?

        cc is equivalent to int3(interrupt) in machine code, which plays the role of breakpoint. It is equivalent to that all int3int3int3 is filled in the function.

        If you accidentally jump to the stack space of the function during code execution, the program can stop immediately,

Class declaration and implementation separation

class Person {
private:  
    int m_age;
public: 
    void setAge(int age);
    // It's all a statement  
    int getAge();
    Person();   
    ~Person();
}
void Person::setAge(int age) {  
    m_age = age;
}
int Person::getAge() { 
    return m_age;
}
Person::Person() { 
    m_age = 0;
}
Person::~Person() {   

}

You can put the class containing the function declaration into the h file, put the function implementation in cpp file

Keywords: C++

Added by Osiris Beato on Mon, 24 Jan 2022 02:07:58 +0200