1. Preliminary Understanding of Procedural and Object-Oriented ProgrammingThe C language is procedural, focusing on processes, analyzing the steps to solve problems, and gradually solving problems through function calls.
●C++ is object-oriented, focusing on objects, breaking down a task into different objects, and completing it through interactions between objects.
2. Introduction to Classes●In C language, a structure can only define variables, while in C++, a structure can define both variables and functions. For example: previously implemented stack in basic data structures using C language, where the structure could only define variables; now implemented in C++, we find that struct can also define functions.●Here, we will not introduce the usage of C language.●C++ is compatible with C, and the previously written structure has been upgraded to a class. Let’s look at the code below:991234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
typedef int DataType;
struct Stack{ // Member function void Init(size_t capacity = 4) { _array = (DataType*)malloc(sizeof(DataType) * capacity); if (nullptr == _array) { perror("malloc申请空间失败"); return; } _capacity = capacity; _size = 0; } void Push(const DataType& data) { // Expand capacity _array[_size] = data; ++_size; } DataType Top() { return _array[_size - 1]; } void Destroy() { if (_array) { free(_array); _array = nullptr; _capacity = 0; _size = 0; } } // Member variables DataType* _array; size_t _capacity; size_t _size;};
int main(){ Stack s; s.Init(10); s.Push(1); s.Push(2); s.Push(3); cout << s.Top() << endl; s.Destroy(); return 0;}
●The definition of the above structure is more commonly replaced by the<span><span>C++</span></span> keyword class. Below is the definition of a class and its usage:91234
class className{ // Class body: consists of member functions and member variables}; // Note the semicolon at the end
●class is the keyword for defining a class,<span><span>ClassName</span></span> is the name of the class,<span><span>{}</span></span> contains the body of the class, and note that the semicolon at the end of the class definition cannot be omitted.●The contents within the class body are called class members: variables in the class are called class properties or member variables; functions in the class are called class methods or member functions.How to write it?●We can define a Date class, but we recommend adding an underscore<span><span>_</span></span> for distinction:9123456
class Date{ int year; int month; int day;};
●If written this way, it becomes indistinguishable:99123456789101112
class Date{ void Init(int year,int month,int day) { year = year; month = month; day = day; } int year; int month; int day;};
●So it should be written like this:99123456789101112
class Date{ void Init(int year,int month,int day) { _year = year; _month = month; _day = day; } int _year; int _month; int _day;};
●At this point, can we use the functions within this class?9123456
int main(){ Date d1; d1.Init(2024, 1, 26); return 0;}
●We find that it reports an error, what does this indicate?
C++ introduces three access specifiers, let’s take a look:3. Access Specifiers and Encapsulation in ClassesAccess Specifiers●C++ implements encapsulation by: combining the properties and methods of an object within a class, making the object more complete, and selectively providing its interface to external users through access permissions.
[Access Specifier Explanation]1.Members modified by public can be accessed directly outside the class2.Members modified by protected and private cannot be accessed directly outside the class (protected and private are similar here)3.The scope of access permissions starts from the position where the access specifier appears until the next access specifier appears4.If there are no access specifiers afterwards, the scope extends to <span><span>}</span></span> which indicates the end of the class.5.The default access permission for class is private, while for struct it is public (because struct needs to be compatible with C)Note: Access specifiers are only useful at compile time; once data is mapped to memory, there is no distinction based on access specifiers.The above code can be written as follows:9912345678910111213141516171819202122
class Date{ // public, will be modified until the end or until the next specifier appears public: void Init(int year,int month,int day) { _year = year; _month = month; _day = day; } int _year; int _month; int _day;};
int main(){ Date d1; class Date d2; // This is also acceptable d1.Init(2024, 1, 26); d2._day++; return 0;}
●Or let’s look at this:○Even if changed to<span><span>struct</span></span> it is the same
●Then if I add a function at the top, can it be accessed?○Clearly, it can be accessed because there are no access specifiers restricting it; the defined struct is public by default, while class is private.
●Class cannot access
●Assuming a class is large and requires separation of declaration and definition Here we can see an error occurred because the compiler searches by default in the global scope and does not search within the class, resulting in an error.
●At this point, adding a<span><span>::</span></span> will specify the search scope like a namespace.●Now, adding it again raises another error; we previously discussed that default parameters cannot be given in both declaration and definition.
●Default parameters can only be given in the declaration. After further improvement:
●Priority will search in the specified scope, if not found, then search in the local scope, and finally in the global scope.[Interview Question] The difference between struct and class in C++Question: What is the difference between struct and class in C++?●Answer: C++ needs to be compatible with C language, so struct in C++ can be used as a structure. Additionally, struct in C++ can also be used to define classes. The difference is that<span><span>struct defined classes have a default access permission of public</span></span>, while<span><span>class defined classes have a default access permission of private</span></span>. Note: There are also differences in inheritance and template parameter lists.Two ways to define a class1.Declare and define everything within the class body, noting that: If member functions are defined within the class, the compiler may treat them as inline functions.
2.Class declarations are placed in .h files, and member function definitions are placed in .cpp files. Note: Class names need to be prefixed with the class name<span><span>::</span></span>
●Generally, the second method is preferred.4. Encapsulation[Interview Question] The three main characteristics of object-oriented programming●The three main characteristics of object-oriented programming: Encapsulation, Inheritance, Polymorphism.1.C++ places both data and methods within the class2.C++ uses access specifiers to restrict members; if access is allowed, it is public; if not, it is private.At the class and object stage, the main focus is on studying the encapsulation characteristics of classes. So what is encapsulation?Encapsulation: organically combining data and methods that operate on the data, hiding the object’s properties and implementation details, and only exposing interfaces for interaction with the object.●Encapsulation is essentially a form of management, making it easier for users to use the class. For example: for a complex device like a computer, the user is only provided with the power button, keyboard input, monitor, USB ports, etc., allowing interaction with the computer to complete daily tasks. However, the actual workings of the computer involve hardware components like the CPU, graphics card, memory, etc.●For computer users, there is no need to concern themselves with the internal core components, such as how the motherboard’s wiring is laid out or how the CPU is designed; users only need to know how to power on the computer and how to interact with it using the keyboard and mouse. Therefore, computer manufacturers enclose the internal implementation details in a shell, only providing external interfaces like the power button, mouse, and keyboard ports for user interaction.In C++, encapsulation can be implemented through classes that hide data and methods, controlling which methods can be used directly outside the class.5. Scope of Classes●A class defines a new scope, and all members of the class are within the class’s scope. When defining members outside the class, the<span><span>::</span></span> scope operator is needed to indicate which class domain the member belongs to.6. Instantiation of ClassesThe process of creating an object using a class type is called class instantiation.1.A class describes an object; it is like a model that defines what members a class has. Defining a class does not allocate actual memory space to store it; for example, the student information form filled out during enrollment can be seen as a class describing specific student information.2.A class can instantiate multiple objects, and the instantiated objects occupy actual physical space to store class member variables.●Members defined within a class are declarations and do not occupy space.
●Writing it this way, instantiating first and then assigning values is acceptable.
●The Person class does not occupy space; only the objects instantiated from the Person class have specific ages.3.For example, instantiating an object from a class is like using architectural blueprints to build a house; the class is like the blueprint, only designing what is needed, but no physical building exists. Similarly, a class is just a design; only instantiated objects can actually store data and occupy physical space.
7. Class Object ModelQuestion: A class can have both member variables and member functions, so what does an object of a class contain? How is the size of a class calculated?Storage method of class objects●An object contains the various members of the class.
Defect: Each object has different member variables, but calls the same function. If stored this way, when a class creates multiple objects, each object will save a copy of the code, wasting space. So how to solve this?●Code is saved only once, and the object saves the address where the code is stored.
●Only member variables are saved, while member functions are stored in a common code segment.
●Question: Among the above three storage methods, which one does the computer actually use?We can analyze by getting the size of different objects:99123456789101112131415161718
class Date{ void Init(int year, int month, int day) { _year = year; _month = month; _day = day; } int _year; int _month; int _day;};
int main(){ Date d1; cout << sizeof(d1) << endl;}
●It can be clearly seen that this is the size of the three members, while the functions are not counted.
●Conclusion: The size of a class is actually the sum of its “member variables”. Note that memory alignment and the size of empty classes [similar to C language] are special; the compiler gives an empty class one byte to uniquely identify the object’s class.Let’s recall the memory alignment rules for structures:1.The first member is at the address with an offset of 0 from the structure.2.Other member variables must be aligned to an integer multiple of a certain number (alignment number).●Note: Alignment number = the smaller value between the compiler’s default alignment number and the size of the member. In VS, the default alignment number is 8.3.The total size of the structure is: the maximum alignment number (the largest of all variable types and the minimum of the default alignment parameter).4.If nested structures are involved, the nested structure must be aligned to its own maximum alignment number, and the overall size of the structure is an integer multiple of all maximum alignment numbers (including nested structures).[Interview Questions]1.How does a structure align? Why is memory alignment necessary?2.How to align a structure according to specified alignment parameters? Can it be aligned to any byte, such as 3, 4, 5?3.What is big-endian and little-endian? How to test whether a machine is big-endian or little-endian, and have you encountered scenarios where endianness needs to be considered?8. Introduction to the this Pointer●Let’s first define a Date class<span><span>Date</span></span>, what will the result of the following code be?99123456789101112131415161718192021222324252627282930
class Date{public: void Init(int year, int month, int day) { _year = year; _month = month; _day = day; } void print() { cout << _year << "-" << _month << "-" << _day << endl; }private: int _year; int _month; int _day; };int main(){ Date d1, d2; d1.Init(2022, 5, 11); d2.Init(2022, 5, 12);
d1.print(); d2.print(); return 0;}
●We can see that it prints out two dates; how does it know which one to print?
●Let’s analyze it by looking at the assembly code: We see that the code calls the same function, so how does the compiler know which of the two dates it is?●Actually, C++ has an implicit this pointer●When using the function, an address is passed, and an implicit this pointer receives it.The prototype looks like this:
●We see that the code calls the same function, so how does the compiler know which of the two dates it is?●Actually, C++ has an implicit this pointer that is passed to member functions, allowing them to access the object’s members.In member functions, this pointer is a constant pointer, meaning it cannot be modified.We can print the address of the this pointer in the class, and then print the addresses of<span><span>d1</span></span> and<span><span>d2</span></span> to see:
●The result shows that the this pointer points to a pointer to the current object.●We can also do it this way, which will not cause an error, but we cannot write it directly in the parameter as above.
Characteristics:1. The type of the this pointer is: type *const, meaning that in member functions, the this pointer cannot be assigned a value.2. It can only be used within member functions.3. The this pointer is essentially an implicit pointer parameter of the member function; when an object calls a member function, the object’s address is passed as an argument to the this parameter. Therefore, the this pointer is not stored in the object.4. The this pointer is the first implicit pointer parameter of the member function, generally passed automatically by the compiler through the<span><span>ecx</span></span> register, and does not need to be passed by the user.[Interview Question]1. Where is the this pointer stored?a. Heap b. Stack c. Static area d. Constant area e. Inside the object●First, we can exclude<span><span>e</span></span>, because we know that when calculating the size of the class, the this pointer is not counted, so we exclude<span><span>e</span></span><span><span>●</span></span>C++’s const variables are not in the constant area; we can see that these two addresses are adjacent.
●So what is in the constant area? Values modified by<span><span>const</span></span> are in the constant area; this pointer variable is in the stack, pointing to the first character of the constant string in the constant area, so we can also exclude<span><span>d</span></span>.
●c is even less likely, as static and global variables are in the static area.●a can also be excluded, because malloc is in the heap, and this is not malloc, so we exclude●Finally, it is in the stack, because it is a parameter (some compilers, like VS, may use registers for storage). Different compilers may place it in different locations; it may be in the stack or in registers (the VC++ compiler places it in ECX, while other compilers may differ; normal parameters of member functions are generally stored in the stack, while the this pointer parameter is stored in registers).●By opening the assembly, we can also see that the lea instruction is load effective address, which loads the value of<span><span>ecx</span></span> into[d1].
2..Can the this pointer be null?First question: What is the result of the following program? A. Compilation error B. Runtime crash C. Normal operation9912345678910111213141516
class A{public: void Print() { cout << "Print()" << endl; }private: int _a;};
int main(){ A* p = nullptr; p->Print(); return 0;}
●It has run perfectly, because I did not access the object’s content, so it can run normally.
Second question: What is the result of the following program? A. Compilation error B. Runtime crash C. Normal operation991234567891011121314151617
class A{public: void PrintA() { cout << _a << endl; }private: int _a;};
int main(){ A* p = nullptr; p->PrintA(); return 0;}
●This raises a null pointer, because I need to print the<span><span>_a</span></span>, which requires finding that block of space.
●It can also be written like this, the this pointer is a null pointer, and dereferencing will cause an error.
Therefore, the this pointer can be null, as long as its content is not accessed within member functions, the program can run normally.