[C++ Basics] 2. Classes and Objects (Part 1) (10,000 words to master the core content of C++ classes)


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 solving the problem step by step through function calls

C++ is based on object-oriented, focusing on objects, splitting one thing into different objects, and relying on the interaction between objects to complete.

Take the takeaway in our life as an example:

The process-oriented focus is on how to realize the functional modules from meal selection, ordering, delivery, and pickup step by step.

Object-oriented concerns are: ordering users and user operations (such as ordering, evaluation, etc.), restaurant stores and corresponding operations (adding new dishes, deleting dishes, setting prices, etc.), food delivery personnel (location, path planning, etc.) , order, etc.)

It can be clearly felt that one focuses on the process and its implementation, and the other focuses on each object and its operation.

Process-oriented: data and methods are separated

Object-oriented: data and methods are encapsulated together

2. The introduction of the class

In C language, only variables can be defined inside a structure. In C++, not only variables but also functions can be defined inside the structure. That is to say, there are both data (member variables) and methods (member functions) inside the structure.

//C语言中struct的使用方式
struct SNode
{
    
    
	int val;
	struct SNode* next;//这里必须要struct SNode*,不能直接使用SNode*
};
struct SNode
{
    
    
    void InitSNode();//可以直接在结构体内部定义函数
    void PrintSNode();
    void PushSNode(int x);
	int val;
	SNode* next;//这里可以直接使用SNode*,C++中结构体定义中默认设置了typedef功能,
    //所以不需要额外的typedef
};

After the structure keyword struct of C language arrived in C++, it not only continued to use the original C syntax, but also upgraded it to a class.

Although you can use struct to define classes directly, in C++, you prefer to use class instead of struct. (class is a keyword, indicating a class)

3. Class Definition

class className
{
    
    
	//类体:由成员变量和成员函数组成
};//要注意这里有分号;

classThe keyword for defining the class, ClassNamethe name of the class, and the body of the class in curly brackets { }. Note that there is a semicolon after the end of the class definition.

The elements in the class are called members of the class: the data in the class is called the attributes or member variables of the class; the functions in the class are called the methods or member functions of the class.

There are two ways to define a class:

1) All declarations and definitions are placed in the class body.

Note: If a member function is defined in a class, the compiler may treat it as an inline function.

//方式一:声明和定义全在类内部
class SNode
{
    
    
public:
	void ShowVal()
	{
    
    
		cout << val << endl;
	}
private:
	int val;
    SNode* next;
};

2) The declaration and definition are separated, the declaration is placed in the .h file, and the definition is placed in the .cpp file

//在SNode.h文件中声明
#include<iostream>
using namespace std;
//方式一:声明和定义全在类内部
class SNode
{
    
    
public:
	void ShowVal();
private:
	int val;
	SNode* next;
};
//在SNode.c中实现函数
#include"SNode.h"
void SNode::ShowVal()//这里主要要使用SNode::,类名+域作用符,否则找不到函数
{
    
    
	cout << val << endl;
}

In general, the second approach is more recommended, separating declarations and definitions.

4. Class access qualifiers and encapsulation

4.1 Access Qualifiers

The way C++ implements encapsulation: use classes to combine the attributes and methods of an object to make the object more complete, and selectively provide its interface to external users through access rights.

image-20220316205223450

【Access Qualifier Description】

1) publicModified members can be accessed directly outside the class

2) protectedand privatemodified members cannot be directly accessed outside the class (here protectedand privateare similar)

3) The scope of access rights starts from the position where the access qualifier appears until the next access qualifier appears, and if there is no next access qualifier, it goes to the position where the curly braces { } end.

4) classThe default access permission is private, structthe default access permission is public(because it structis 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

【Interview questions】

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 can also be used to define classes in C++. It is the same as class is to define a class, the difference is that the default access mode of members of struct is public, and the default access mode of members of class is private.

4.2 Packaging

[Interview questions] The three major characteristics of object-oriented: encapsulation, inheritance, polymorphism. (Other features: abstraction, reflection (Java))

In the class and object stage, we only study the encapsulation characteristics of classes, so what is encapsulation?

Encapsulation: Organically combine data with methods for manipulating data, hide the properties and implementation details of objects, and only expose interfaces to interact with objects.

The definition and design of the class reflects the idea of ​​encapsulation.

Encapsulation is essentially a management : how do we manage the Terracotta Warriors?

For example, if nothing is left, the Terracotta Warriors will be destroyed at will. Then we first built a house to encapsulate the Terracotta Warriors. But our purpose is not to encapsulate it so that others can't see it. Therefore, we have opened the ticket sales channel, and you can buy tickets to break through the package and go in and visit under a reasonable supervision mechanism. The same is true of classes, we use classes to encapsulate data and methods together. If we don't want others to see it, we use protected/privateencapsulation of members. At the same time, publicopen some common member functions to make reasonable access to member variables. So the essence of encapsulation is a kind of management.

Question: To encapsulate or not to encapsulate? Why?

A: Well packaged.

No encapsulation, more freedom, although you can access data and methods at will, but the people who need to use it understand the specifications better and can abide by the rules, otherwise it is easy to break the data

Encapsulation, data and methods are placed in classes, those you want to access are defined as public, those you don’t want to access are defined as private, and you are forced to abide by the rules

#include<iostream>
using namespace std;

//如何定义一个类class?
//封装
//1、将数据和方法定义到一起
//2、把想给你看到的数据定义成公有类型public展示,
//不想给你看的内容封装起来(private、protected),访问限定符。
class Stack //相当于声明
{
    
    
	//1、成员函数
	//通过成员函数来访问和修改成员变量
public:
	void Push(int x);
	void Pop();
	bool Empty();

	//2、成员变量
private:
	int* _a;
	int _size;
	int _capacity;

};
//1、C语言中struct是用来定义结构体的
//2、C++中,兼容C的struct定义结构体的用法,但是同时sturct也可以用来定义类。
//3、C++中使用class和struct定义类的区别? 默认的访问限定符不同 class默认为private struct默认public

struct ListNode_C
{
    
    
	int val;
	struct ListNode_C* _next;
	struct ListNode_C* _prev;
};

struct ListNode_CPP
{
    
    
	int val;
	struct ListNode_CPP* next;//兼容C语言
	ListNode_CPP* _prev;//可以直接用ListNode_CPP* 表示一个类
	//还可以定义函数
	ListNode_CPP* CreateNode(int val);
};

int main()
{
    
    
	//类实例化出对象,相当于定义出了类的成员变量
	//相当于拿着设计图纸去建造具体的房子
	Stack s1;
	Stack s2;
	Stack s3;
	//s1.a = nullptr;//private 成员不能在外面直接访问
	s1.Push(1);//Puch只是声明,没有定义
	//类中声明的函数定义的两种方式 类里面定义  类外面定义
	return 0;
}

void Stack::Pop()//需要指明函数所属类的名称
{
    
    
	//...
}

【Interview questions】

What is the difference between declaration and definition?

A statement is a promise. It promises to do something, but it has not been done yet. The definition is to implement the promised thing.

class classname{
    
    
//…成员函数、成员变量
}

This is the class declaration, and if you use this class to create an object, that's the class definition.

5. Class Scope

A class defines a new scope, and all members of the class are in the scope of the class. To define a member outside the class body (that is, outside the class {} curly braces), you need to use the :: scope resolver to indicate which class scope the member belongs to. Otherwise, the compiler may not find the class domain to which this member belongs, resulting in compilation failure.

class Person
{
    
    
public:
	void PrintPersonInfo();
private:
	char _name[20];
	char _gender[3];
	int _age;
};
//这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
    
    
	cout << _name << " "<<_gender << " " << _age << endl;
}

6. Class instantiation

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

1. A class is just a model, which defines the members of the class. Defining a class does not allocate actual memory space to store it.

2. A class can instantiate multiple objects. The instantiated objects occupy the actual physical space and store class member variables.

3. Make an analogy. A class instantiating an object is like building a house using architectural design drawings 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, which is instantiated. Objects can actually store data and occupy physical space

Comparative understanding: The instantiation of a class is the same as creating a variable of that type with a certain type. For example, using an int type to create a variable of the int type is the instantiation of the int type. The int type itself does not occupy storage space, similar to the design For drawings, only using int type to create an int type variable will occupy the actual space, which is similar to building a house according to the drawings.

image-20220316212019273

image-20220316211558744

Note: The member variable declaration is telling us the type and name of the variable, but it does not open up storage space. The definition of variables and objects opens up storage space, which has nothing to do with initialization.

7. Class Object Model

7.1 How to Calculate the Size of a Class Object

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

Question: A class can have both member variables and member functions, so what is contained in the object of a class (the instantiation of the class)? How to calculate the size of a class?

7.2 Guessing how class objects are stored

Method 1: There are both member variables and member functions.

image-20220316213146662

Defect: The member variables in each object are different, but the same function is called, if stored in this way, when a class creates multiple objects, each object will save a piece of code, the same code is saved multiple times, Waste of space. So how to solve it?

2) Only save member variables, member functions are stored in the public code segment

image-20220318115440975

Question: For the above two storage methods, in which way is the computer stored?

We then analyze the following different objects

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

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

image-20220316214037891

Question: Why are A2 and A3 here 1 instead of 0?

Opening 1 byte here is not to store data, but to occupy a place to indicate its existence.

Conclusion: The size of a class is actually the sum of the "member variables" in the class. Of course, memory alignment is also required. Pay attention to the size of the empty class. The empty class is special. The compiler gives the empty class a byte to uniquely identify this. kind.

What does an empty class do?

Empty class: functor, this type is defined to do some identification and identify the type of iterator. (Empty classes are valuable, but our current knowledge reserve is not enough, we will learn it later~)

7.3 Structure memory alignment rules

1) The first member is at the address at offset 0 from the structure.

2) Other member variables should be aligned to an address that is an integer multiple of a certain number (alignment number).

Note: Alignment = the smaller of the compiler's default alignment 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 number of alignments (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 of all maximum alignment numbers (including the alignment number of nested structures). times.

【Interview questions】

1. How is the structure aligned? Why is memory aligned?

2. How to align the structure according to the specified alignment parameters?

3. What is big-endian? How to test whether a machine is big-endian or little-endian? Have you ever encountered a scenario where big-endian or little-endian must be considered?

8. This pointer of class member function

8.1 The derivation of this pointer

Let's first define a date class Date

class Date
{
    
    
public:
	void Display()
	{
    
    
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	void SetDate(int year, int month, int day)
	{
    
    
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};

image-20220317075011136

For the above class, there is a problem like this:

There are two member functions, SetDate and Display, in the Date class. There is no distinction between different objects in the function body. When s1 calls the SetDate function, how does the function know that the s1 object should be set instead of the s2 object?

In C++, this problem is solved by introducing (implicit) this pointer, that is, the C++ compiler adds a hidden pointer parameter to each "non-static member function", allowing the pointer to point to the current object (the function is called when the function is running). object of the function), the operation of all 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, and the compiler completes it automatically.

image-20220317075051571

Of course, the actual call has also done some processing

image-20220317075115846

The this pointer points to the calling object. (Whoever calls this pointer, this pointer points to)

class Date
{
    
    
public:
	//void Display(Date* this)
	void Display()
	{
    
    
		cout << _year << "-" << _month << "-" << _day << endl;
		//cout << this->_year << "-" << this->_month << "-" <<this-> _day << endl;
	}
	//void SetDate(Date* this,int year,int month,int day)
	void SetDate(int year, int month, int day)
	{
    
    
		_year = year;//this->_year = year;
		_month = month;//this->_month = month;
		_day = day;//this->_day = day;
	}
private:
	int _year;//年
	int _month;//月
	int _day;//日
};
int main()
{
    
    
	Date d1, d2;
	d1.SetDate(2021, 8, 19);//d1.SetDate(&d1,2021,8,19)
	d2.SetDate(2021, 8, 20);//d2.SetDate(&d2,2021,8,19)
	d1.Display();//d1.Display(&d1)
	d2.Display();//d2.Display(&d2)
	return 0;
}

8.2 Characteristics of this pointer

1) The type of this pointer: class type * const

2) can only be used inside a "member function"

3) This pointer is actually a formal parameter of a member function. When an object calls a member function, the object address is passed as an actual parameter to the this formal parameter. So 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.

image-20220317080006163

【Interview questions】

1) Where does this pointer exist? (That is, which area of ​​the process address space exists?)

Answer: On the stack, the this pointer is a formal parameter, which is only created when the function is called and exists in the stack area. (Special case: the this pointer under vs is stored in the ecx register)

image-20220317080034647

2) Can this pointer be null?

#include<iostream>
using namespace std;
//1.下面程序能编译通过吗?
//2.下面程序会崩溃吗?在哪里崩溃?
class A
{
    
    
public:
	void PrintA()
	{
    
    
		cout << _a << endl;
	}
	void Show()
	{
    
    
		cout << "Show()" << endl;
	}
private:
	int _a;
};
int main()
{
    
    
	A* p = nullptr;
	p->PrintA();
	p->Show();
	return 0;
}

image-20220317080135322

image-20220317080142543

p->PrintA();//崩溃
p->Show();//正常运行

Cause Analysis:

p->PrintA();//崩溃

The value of _a is printed in PrintA(), that is, the member variable is accessed, and a this pointer is implied, PrintA()—> PrintA(A* this)

The p->PrintA() call will access the _a member in the object pointed to by the pointer p, but the p pointer itself is a null pointer nullptr, which points to an empty space and has no pointed object. To access the content pointed to by a nullptr, it is also It is the dereference operation of the null pointer, which is an illegal operation!

p->Show();//正常运行

The Show() function just prints "show()" and does not access the members of the object. That is, although the Show() function contains the this pointer, Show()—> Show(A* this), it does not access the this pointer, and naturally there will be no illegal access.

The addresses of member functions are not stored in the object, but in the public code segment. The member function is called here, and the space pointed to by p will not be accessed, so there is no problem of dereferencing the null pointer. Here only p is passed to the implicit this pointer, but the Show( ) function also does not dereference the this pointer.


Mind map summary

insert image description here

Guess you like

Origin blog.csdn.net/QIYICat/article/details/123657272