Detailed explanation of C++ (classes and objects) - 1

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

Insert image description here
In a process-oriented design, we might define a series of functions to perform each of the above steps. Each function may accept some parameters (such as laundry list, quantity of washing powder, etc.) and return some results (such as washing completion time, list of dry clothes after drying, etc.). Data (such as laundry and laundry detergent) may be passed between these functions, and the relationship between the functions is loose, passing data through parameters and return values.

C++ is based on object-oriented and focuses on objects. Splitting one thing into different objects relies on the interaction between objects .

Insert image description here
When washing clothes in a washing machine, there are four objects: people, washing machines, washing powder, and clothes .

The entire process of washing clothes: people put the clothes into the washing machine, pour in the washing powder, start the washing machine, and the washing machine will complete the washing process and spin dry.
The whole process is mainly completed through the interaction between four objects : people, washing machines, washing powder, and clothes . People do not need to care about how the washing machine washes clothes or how to dry them.

1. In the process-oriented laundry process, we split the entire process into a series of functions, and data is passed between functions.
2. In the object-oriented laundry process, we regard the entire process as the interaction between the washing machine object and the clothing object. Each object encapsulates its own data and methods, and the interaction is achieved through method calls. The two methods have different advantages and applicable scenarios when solving problems and organizing code.

2. Introduction of classes

Only variables can be defined in the C language structure. In C++, not only variables but also functions can be defined in the structure .

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 it is implemented in C++, and you will find that functions can also be defined in the struct :

struct Stack
{
    
    
	void Init(size_t capacity)
	{
    
    
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (nullptr == _array)
		{
    
    
			perror("malloc申请空间失败");
			return;
		}
		_capacity = capacity;
		_size = 0;
	}
	void Push(const DataType& data)
	{
    
    
		// 扩容
		_array[_size] = data;
		++_size;
	}
	DataType Top()
	{
    
    
		return _array[_size - 1];
	}
	void Destroy()
	{
    
    
		if (_array)
		{
    
    
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
	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 structure above is preferred to be replaced by class in C++.

3. Class definition

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

class is the keyword that defines the class, ClassName 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. Please note: if a member function is defined in a 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 class name needs to be added before the member function name::
Insert image description here

Note: Under normal circumstances, in actual work, the second method is more used, which is easier to manage.


Suggestions for member variable naming rules:

Let's take a look at this function. Is it very rigid?

class Date
{
    
    
public:
	void Init(int year)
	{
    
    
		// 这里的year到底是成员变量,还是函数形参?
		year = year;
	}

So this is generally recommended:

class Date
{
    
    
public:
	void Init(int year)
	{
    
    
		_year = year;
	}
private:
	int _year;
};

Or this:

class Date
{
    
    
public:
	void Init(int year)
	{
    
    
		mYear = year;
	}
private:
	int mYear;
};

Other methods are also possible, depending on the company's requirements. Generally, it is enough to add a prefix or suffix to identify them.

4. Class access qualifiers and encapsulation

4.1 Access qualifiers

The way C++ implements encapsulation: Use classes to combine the properties and methods of objects to make the objects more complete, and selectively provide their interfaces to external users through access rights.
Insert image description here[Access Qualifier Description]
1. Public-modified members can be directly accessed outside the class
2. Protected and private -modified members cannot be directly accessed outside the class (protected and private are similar here)
3. Access permission scope Starting from the position where the access qualifier appears until the next access qualifier appears
4. If there is no subsequent access qualifier, the scope ends at }, which is the end of the class.
5. The default access rights of class are private and struct is public (because struct must be compatible with C).
Note: Access qualifiers are only useful at compile time. When the data is mapped to memory, there is no difference in access qualifiers.

Example:


class Date
{
    
    
public:
	//显示日期信息
	void Print()
	{
    
    
		cout << _year << '/' << _month << '/' << _day << endl;
	}
private:
	int _year=2023;//年
	int _month=12;//月
	int _day=31;//日
};

int main()
{
    
    
	Date d1;
	d1.Print();
	d1._year;//该代码会报错
	return 0;
}

When we use d1 to access the Print function, we can access it normally:
Insert image description here
but when we try to access the private members in the Date class, the compiler will report an error:
Insert image description here

[Interview Question] 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

[Interview questions]

The three major characteristics of object-oriented: encapsulation, inheritance, and polymorphism.

In the class and object stage, we mainly study the encapsulation characteristics of classes. So what is encapsulation?

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
For computer users, there is no need to worry about the internal core components, such as how the circuits on the motherboard are laid out,
how 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.

To implement encapsulation in the C++ language, data and methods for operating data can be organically combined through classes, and access rights can be used to hide the internal implementation details of objects and control which methods can be used directly outside the class.

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.
Insert image description here

6. Instantiation of classes

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

  1. 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; for example: the student information form filled in when enrolling, a form can be Think of it as a class to describe specific student information.
  2. A class can instantiate multiple objects. The instantiated objects occupy actual physical space. The storage class member variables are as follows: The Person class has no space. Only objects instantiated by the Person class have specific gender. and age.

    Insert image description here

Let’s use an analogy. Instantiating objects from a class is like using architectural blueprints to build a house in reality, and classes are like blueprints. Only
what is needed is designed, but no physical building exists. Similarly, the class is just a design, and the instantiated objects
can actually store data and occupy physical space.

7. Calculation of class object size

7.1 How to calculate the size of a class object

class A
{
    
    
public:
	void PrintA()
	{
    
    
		cout << _a << endl;
	}
private:
	char _a;
};

Question: How to calculate the size of a class?
You can use the sizeof operator to calculate the size of a class, as follows:

class A
{
    
    
public:
	void PrintA()
	{
    
    
		cout << _a << endl;
	}
private:
	char _a;
};
int main()
{
    
    
	cout << sizeof(A) << endl;
    return 0;
}

Insert image description here

7.2 Storage method of class objects

The class only saves member variables, and member functions are stored in the public code section.

Example:


// 类中既有成员变量,又有成员函数
class A1 {
    
    
public:
	void f1() {
    
    }
private:
	int _a;
};
// 类中仅有成员函数
class A2 {
    
    
public:
	void f2() {
    
    }
};
// 类中什么都没有---空类
class A3
{
    
    };

int main()
{
    
    
	cout << "A1:" << sizeof(A1) << endl;
	cout << "A2:" << sizeof(A2) << endl;
	cout << "A3:" << sizeof(A3) << endl;
	return 0;
}

Running results:
Insert image description here
The following is a diagram of the storage method of class objects:

Insert image description here

Conclusion: 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 and the size of the empty class. The empty class is special. The compiler gives the empty class a byte to uniquely identify the class . object.

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 is an integer multiple of all the maximum alignment numbers (including the alignment number of nested structures) .

8. This pointer of class member function (emphasis)

8.1 Introduction of 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;
}
int main()
{
    
    
	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 the d2 object?

This problem is solved in C++ by introducing the this pointer, namely:

The C++ compiler adds a hidden pointer parameter to each "non-static member function", allowing the pointer to 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, They are all 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.

Illustration:
Insert image description here

8.2 Characteristics of this pointer

1. Type of this pointer: Class type * const, that is, in member functions, this pointer cannot be assigned a value, but the value pointed to by this pointer can be changed.
2. It cannot be written explicitly in the formal parameters and actual parameters, and can only be used inside the "member function" .
3. The this pointer is essentially the formal parameter of the "member function". When the object calls the member function, the function passes the object address as an actual parameter to the this parameter (the this pointer points to the current object). 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, it is automatically passed by the compiler through the ecx register and does not need to be passed by the user .

Illustration:
Insert image description here

8.3 Practice it

  1. What is the result of compiling and running the following program? A. Compilation error B. Running crash C. Normal operation
class A
{
    
    
public:
	void Print()
	{
    
    
		cout << "Print()" << endl;
	}
private:
	int _a;
};
int main()
{
    
    
	A* p = nullptr;
	p->Print();
	return 0;
}

Answer:C
Insert image description here

Then some veterans may ask: Isn’t a null pointer unable to be dereferenced?
In fact, there is no dereference at all. The Print function is stored in the public code area , and its address has been processed during the compilation stage. Just like ordinary function calls, it is called directly through the function name calling rules. The address of the function is enough. p is a null pointer, which is equivalent to passing the null pointer to this. However, since the this pointer does not access specific object members, it runs normally .

  1. What is the result of compiling and running the following program? A. Compilation error B. Running crash C. Normal operation
class A
{
    
    
public:
    void PrintA()
    {
    
    
        cout << _a << endl;
    }
private:
    int _a;
};
int main()
{
    
    
    A* p = nullptr;
    p->PrintA();
    return 0;
}

Answer: B
The this pointer becomes a null pointer after receiving the actual parameters. The this pointer has been made empty and no longer points to the address of the current object. However, if you still want to access the object _a of the current class, you must dereference the null pointer. , it will collapse at this time. We can also observe this through debugging.
Insert image description here
Insert image description here

3.Where does this pointer exist?
The this pointer is a formal parameter. The formal parameter is in the stack frame of the function. The variables in the stack frame of the function belong to the stack.
Sometimes the compiler will optimize it using registers, and the this pointer will be stored in a register.

(End of chapter)

Guess you like

Origin blog.csdn.net/originalHSL/article/details/131870257