[C++ Getting Started Guide] Classes and Objects (Part 1)


Insert image description here


1. Preliminary understanding of process-oriented and object-oriented

 C language is process-oriented , focusing on the process , analyzing the steps to solve the problem, and gradually solving the problem through function calls.
Insert image description here


 C++ is based on object-oriented and focuses on objects . It splits one thing into different objects and relies on the interaction between objects.
Insert image description here


2. Introduction of classes

Only variables can be defined in C language structures. In C++, when a structure is upgraded to a class, not only variables but also functions can be defined.. For example: in the initial stage of data structure, when the stack was implemented in C language, only variables could be defined in the structure ; now when it is implemented in C++, you will find that functions can also be defined in the struct.

Cpp code demonstration :

struct Stack
{
    
    
	//函数
	void Init()
	{
    
    
		a = nullptr;
		capacity = top = 0;
	}

	void Push(int x)
	{
    
    
		a[top] = x;
		top++;
	}
	// ....其他函数
	
	//变量
	int* a;
	int top;
	int capacity;
};

But inCPP prefers to use class instead of struct, let’s take a look at class usage (the difference between the two will be introduced later).


3. Class definition

class ClassName
{
    
    
// 类体:由成员函数和成员变量组成
};  // 一定要注意后面的分号

classfor defining classesKeywordsClassName is the name of the class, and { } is the main body of the class., note that the semicolon at the end of the class definition cannot be omitted .
The contents in the class body are called members of the class: variables in the class are called attributes or member variables of the class ; functions in the class are called methods or member functions of the class .

Two ways to define classes :

  1. All declarations and definitions are placed in the class body. Note that if a member function is defined in the class , the compiler may treat it as an inline function .
    Insert image description here
  2. The class declaration is placed in the .h file, and the member function definition is placed in the .cpp file. Note: The member function name needs to be preceded byClass name::
    Insert image description here

4. Class access qualifiers and encapsulation

4.1 Access qualifiers

C++ usually encapsulates objects and methods together, and provides interfaces to external users through selective access permissions. Access permissions are divided into the following three types: Insert image description here
[Access Qualifier Description] :

  1. Members modified by public can be directly accessed outside the class, while members modified by protected and private are the opposite. (protected and private here are similar)
  2. Access scope begins at the occurrence of this access qualifier and ends at the occurrence of the next access qualifier. If there is no access qualifier later, the scope ends at }, which is the end of the class.
  3. The default access rights of class are private and struct is public. (Because struct must be compatible with C)

Tips: Access qualifiers are only useful at compile time. When the data is mapped to memory, there is no difference in access qualifiers.

[ Classic interview 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. In addition, struct in C++ can also be used to define classes. It is the same as class defining a class. The difference is that the default access permission of a class defined by struct is public, and the default access permission of a class defined by class is private.


4.2 Packaging

Encapsulation : Organically combine data and methods of operating data, hide the properties and implementation details of the object, and only expose the interface to interact with the object.

Encapsulation is essentially a kind of management that makes it easier for users to use classes . For example: For a complex device like a computer, the only things provided to the user are the power on/off button, keyboard input, monitor, USB jack, etc., allowing the user to interact with the computer and complete daily tasks. But in fact, the real work of the computer is the CPU, graphics card, memory and other hardware components.
Insert image description here
But for computer users, they don’t need to worry about the internal core components, such as how the circuits on the motherboard are laid out, how the CPU is designed, etc. Users only need to know how to turn on the computer and how to interact with the computer through the keyboard and mouse. . Therefore, when computer manufacturers leave the factory, they put a shell on the outside to hide the internal implementation details, and only provide power switches, mouse and keyboard jacks to the outside so that users can interact with the computer .


5. Scope of class

A class defines a new scope , and all members of the class are within the scope of the class. When defining members outside a class, you need to use the :: scope operator to indicate which class scope the member belongs to. ( A class is different from other scopes. It is a whole when compiled. When defining a variable, it can be anywhere. The compiler will search globally in the scope of the class. )

[Code Demonstration] :

class Date
{
    
    
public:
	void Print();

private:
	int _year;
	int _month;
	int _day;
};

//类体外定义成员函数
void Date::Print()
{
    
    
	cout << "_year" << "_month" << "_day" << endl;
}

6. Instantiation of classes

The process of creating an object from a class type is called instantiation of the class.

A class describes an object . It is something like a model . It limits the members of the class. Defining a class does not allocate actual memory space to store it. However, a class can instantiate multiple objects, and the instantiated objects occupy actual physical space and store class member variables .

Let’s use an analogy. Instantiating objects from a class is like using architectural design drawings to build a house in reality. A class is like a design drawing. It only designs what is needed, but there is no physical building. Similarly, a class is just a design that is instantiated. Objects can actually store data and occupy physical space.
Insert image description here


7. Class object model

7.1 Storage rules for class objects

Let's first take a look at this code to find the size of classes and objects.

class A
{
    
    
public:
void PrintA()
{
    
    
   cout<<_a<<_i<<_d<<endl;
}

private:
char _a;
int _i;
double _d;
};

A class can have both member variables and member functions. Let me first say that the calculation rules for member variables and structures are the same , but what about member functions?

Since the member variables in each object are different, but the same function is called, if it is stored as a normal function, when a class creates multiple objects, a copy of the code will be saved in each object, and the same code will be saved multiple times, resulting in Waste of space . Therefore, in C++, we only save member variables for classes, while member functions are stored in the public code section .
Insert image description here

7.2 Examples

// 类中既有成员变量,又有成员函数
class A1 {
    
    
public:
    void f1(){
    
    }
private:
    int _a;
};

// 类中仅有成员函数
class A2 {
    
    
public:
   void f2() {
    
    }
};

// 类中什么都没有---空类
class A3
{
    
    };

Find: sizeof(A1) : ______ sizeof(A2) : ______ sizeof(A3) : ______ (result: 4, 1, 1)

Analysis: There is no doubt that the size of A1 is 4byte. However, having only one function in the public code area in A2 does not count, and A3 has absolutely no class. For this special case, C++ defines its size as 1byte (Placeholder, does not store data, only indicates that the object has existed

Summary: The size of a class is actually the sum of the "member variables" in the class. Of course, you must pay attention to memory alignment. Pay attention to the size of the empty class. The empty class is special. The compiler gives the empty class one byte to uniquely identify the object of this class. (Represents a placeholder, does not store data, only indicates that the object has existed

7.3 Structure memory alignment rules

  1. The first member is at offset 0 from the structure.
  2. Other member variables should be aligned to addresses that are integer multiples of a certain number (alignment number).
    Note: Alignment number = the smaller of the compiler's default alignment number and the size of the member.
    The default number of alignments in VS is 8
  3. The total size of the structure is: an integer multiple of the maximum alignment number (the largest of all variable types and the smallest default alignment parameter).
  4. If a structure is nested, the nested structure is aligned to an integer multiple of its own maximum alignment number, and the overall size of the structure is an integer multiple of all the maximum alignment numbers (including the alignment number of nested structures).

[Classic interview questions] :

  1. How to align structures? Why do we need memory alignment?
  2. How to align the structure according to the specified alignment parameters? Can it be aligned according to 3, 4, 5, that is, any byte?
  3. What is big and small endianness? How to test whether a certain machine is big endian or little endian? Have you ever encountered a scenario where big or small endianness has to be considered?

8. this pointer

Let's first define a date class Date

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, 1, 11);
	d2.Init(2022, 1, 12);
	d1.Print();
	d2.Print();
	return 0;
}

For the above class, there is such a problem:
There are two member functions, Init and Print, in the Date class. There is no distinction between different objects in the function body. So when d1 calls the Init function, how does the function know that it should set the d1 object? Instead of setting the d2 object?

C++ solves this problem by introducing the this pointer, that is: the C++ compiler adds a hidden pointer parameter to each "non-static member function", letting the pointer point to the current object (the object that calls the function when the function is running). All operations on "member variables" in the function body are accessed through this pointer. It's just that all operations are transparent to the user, that is, the user does not need to pass it, the compiler automatically completes it.

8.2 Characteristics of this pointer

  1. The type of this pointer: The type of the class is const*, that is, in the member function, the this pointer cannot be assigned a value.
    2.This pointer can only be used inside a "member function". (This cannot be displayed and written in the actual parameter and formal parameter positions, but it can be displayed and used in the class.)
  2. The this pointer is essentially a formal parameter of a "member function". When an object calls a member function, the object address is passed to the this parameter as an actual parameter. Therefore, the this pointer is not stored in the object.
  3. The this pointer is the first implicit pointer parameter of the "member function". Generally, it is automatically passed by the compiler through the ecx register and does not need to be passed by the user.

Insert image description here

8.3 Classic interview questions

Interview questions (1)

[Interview questions]:

  1. Where does this pointer exist?
  2. Can this pointer be null?

Answer: This pointer exists in the stack area. It is not possible to simply assign a null to this, but it can be forced to assign a null directly, but such an operation is generally not performed.

Interview questions (2)

Let’s take a look at this interview question from Tencent:

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
    
    
 void Print()
 {
    
    
 cout << "Print()" << endl;
 }
private:
 int _a;
};
int main()
{
    
    
 A* p = nullptr;
 p->Print();
 return 0;
}
//解析:本题主要在于P是否真的进行了空指针的解引用。
//     由于p指向的成员变量,但Print函数实际存在公共代码区(和全局变量类似)
//      所以实际上编译器是不会对p进行解引用。而是直接去符号表中查找Print函数地址。所以答案为C

// 2.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
    
     
public:
    void PrintA() 
   {
    
    
        cout<<_a<<endl;
   }
private:
 int _a;
};
int main()
{
    
    
    A* p = nullptr;
    p->PrintA();
    return 0;
}
//解析:这上面一样,编译器不会对p进行空指针的解引用,而是将p作为this指针传给PrintA函数。
//      而PrintA函数中,需要通过this(即p的形参)解引用指向_a,对空指针进行非法行为,运行崩溃

Well, this blog ends here, I hope it can help you.
Insert image description here
Insert image description here

Guess you like

Origin blog.csdn.net/Zhenyu_Coder/article/details/133362343