[C++] Classes and objects (on)

Table of contents

1 Introduction

2. Introduction of class

3. Class definition

3.1 Two ways to define a class

4. Class access qualifiers

5. The scope of the class

6. Class instantiation

7. Class object model

7.1 Memory alignment rules

7.1 Storage method of class objects

8. this pointer

8.1 Characteristics of this pointer

8.2 Can this pointer be empty?


1 Introduction

The 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.

Let's give an example to illustrate:

For example, for steaming rice, C language focuses on washing rice -> adding water -> adding rice -> starting the pot -> boiling the pot -> boiling water -> putting in a pot with raw rice -> boiling the pot -> taking out; C++ The focus here is on the objects: people, rice, water, and rice cooker. People don’t need to know if the rice cooker works, they only need to interact with the four objects to complete the task.

2. Introduction of class

Only variables can be defined in a C language structure (struct).

In C++, a new way of playing is added. Not only variables can be defined in the structure, but also functions can be defined .

Example:

struct Person
{
	void personInit()
	{
		cout << "void personInit()" << endl;
	}

	int _age;
	char _name[20];
};
int main()
{
	Person p;
	p.personInit();

	return 0;
}

The definition of the above structure is preferred to use class instead in C++.

3. Class definition

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

class is the keyword to define the class , ClassName is the name of the class, and {} is the body of the class. Note that the semicolon after the end of the class definition cannot be omitted.
The contents of 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 .

3.1 Two ways to define a class

3.1.1 Declarations and definitions are all 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 Person
{
public:
	void PersonInit()
	{
		cout << "void PersonInit()" << endl;
	}

private:
	int _age;
	char _name[20];
};

3.1.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::

//Person.h
class Person
{
public:
	void PersonInit();

private:
	int _age;
	char _name[20];
};


//Person.c
#include "Person.h"
void Person::PersonInit()
{
	cout << "void Person::PersonInit()" << endl;
}

In general, the second approach is more desirable.

Note: Generally, _ (underscore) is added before the member variable when declaring the member variable, in order to distinguish the formal parameters of the member function (as long as it can be distinguished, the former underscore is one of my methods, and the Google C++ specification generally likes to add _ after ).

If the member variable has no special mark, when the member variable is used in the member function and assigned to it, the function will adopt the principle of local priority and assign itself to itself, so that the expected effect cannot be achieved.

4. Class access qualifiers

The way of C++ to achieve encapsulation: use classes to combine the properties and methods of the object to make the object more complete, and
selectively .

【Description of Access Qualifier】

1. Public modified members can be directly accessed outside the class;
2. Protected and private modified members cannot be directly accessed outside the class (here protected and private are similar);
3. The scope of access rights is limited from this access character appears until the next access qualifier appears;
4. If there is no access qualifier behind, the scope will go to }, that is, the end of the class;
5. The default access permission of class is private, and struct is public (because struct requires 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.

5. The scope of the class

A class defines a new scope , and all members of the class are in the scope of the class. When defining members outside the class, you need to use the :: scope operator to indicate which class domain the member belongs to.
For example:

class Person
{
public:
	void PersonInit();//声明

private:
	int _age;
	char _name[20];
};


//初始化定义的时候函数名前加 Person::,表明PersonInit是Person类域的
void Person::PersonInit()//定义
{
	cout << "void Person::PersonInit()" << endl;
}

6. Class instantiation

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

Before instantiation, the defined class does not take up space.
For example:

class Person
{
public:
    void PersonInit()
    {
        cout << "void PersonInit()" << endl;
    }

private:
    int _age;		//声明
    char _name[20];
};

int main()
{
	Person::_age = 20;
    //定义开空间
    Person p;

    return 0;
}

When p is not instantiated, the defined class Person class does not open up space.

The p object is instantiated. At this time, p occupies the actual space and stores the member variables. (After instantiation here, p cannot directly use _age, because it is private, and how to assign and print it will be described later).

A class is like a blueprint.

Instantiating objects from classes is like building a house with blueprints in reality.

Before the house was built, this area did not take up space.

Instantiation is to build a house according to the diagram, which takes up space.

We can use blueprints to build multiple houses that all take up space

7. Class object model

How to calculate the size of the class object?

For example:

class A
{
public:
	void AInit(int a, int b)
	{
		cout << "void AInit(int a, int b)" << endl;
	}

private:
	int _a;
	int _b;
};
class B
{

private:
	int _a;
	int _b;
};
class C
{};
int main()
{
	cout << "类A的大小:" << sizeof(A) << endl;
	cout << "类B的大小:" << sizeof(B) << endl;
	cout << "类C的大小:" << sizeof(C) << endl;

	return 0;
}

operation result:

Summarize:

1. Member functions are not counted in the size of the class;

2. The size of the class is only related to member variables and follows the structure alignment rules;

3. The size of the empty class is 1 byte (no data is stored, just a placeholder, indicating that the object has existed).

7.1 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 value between the compiler's default alignment and the member size.
The default alignment number 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, and the overall size of the structure is the integer of all maximum alignments (including the alignment of the nested structure) times.

7.1 Storage method of class objects

Why do member functions in a class take up no space? Where does the member function exist?

Only class member variables are stored in the instantiated class

Member functions are kept in the public code segment.

Let's draw a picture to understand:

8. this pointer

Let's write a date class here to see:

class Date
{
public:
    void Init(int year, int month, int day)
    {
    _year = year;
    _month = month;
    _day = day;
    }

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

int main()
{
	Date d1;
	d1.Init(2023, 7, 30);

	return 0;
}

Here it seems that the Init function has only three formal parameters

Three parameters are passed when calling

In fact, there is also a this pointer implied here.

Let's draw a picture here to see:

When assigning a value to a member variable here, a this-> will be added before and after to receive reference access.

8.1 Characteristics of this pointer

1. The type of t his pointer: class type * const t, that is, in member functions, the this pointer cannot be assigned a value.
2. It can only be used inside a "member function".
3. The this pointer is essentially the formal parameter of the "member function" . When the object calls the member function, the object address is passed as the 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.

Therefore, when we write, we cannot write like this:

class Date
{
public:
	void Init(Date* this, int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

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

int main()
{
	Date d1;
	d1.Init(&d1, 2023, 7, 30);

	return 0;
}

The this pointer implies that it would be wrong if we added it ourselves.

This cannot be displayed and written at the position of the actual parameter and the formal parameter

But it can be displayed in the class with

as follows:

class Date
{
public:
    //this在实参和形参的位置上不能显示写
    //但是在类里面可以显示的用
	void Init(int year, int month, int day)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}

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

int main()
{
	Date d1;
	d1.Init(2023, 7, 30);

	return 0;
}

8.2 Can this pointer be empty?

Let's look at the following pieces of code:

class Person
{
public:
	void PersonInit()
	{
		cout << "void PersonInit()" << endl;
	}

private:
	int _age;		//声明
	char _name[20];
};

int main()
{
	Person* p = nullptr; //初始化为空指针
	p->PersonInit();

    return 0;
}

operation result:

Here we will have questions, why can p be dereferenced when it is a null pointer? Still running normally.

Here, if the function is defined in the class and is short, the compiler will treat it as an inline function and expand it directly without dereferencing;

And if the declaration is separated from the definition or the compiler does not treat it as an inline function, it is the address of the call Init function (calling function), nor is it dereferenced.

Let's continue to look at:

class Person
{
public:
	void PersonInit()
	{
		cout << "void PersonInit()" << endl;
	}

//private:
	int _age;		//声明
	char _name[20];
};

int main()
{
	Person* p = nullptr; //初始化为空指针
	p->PersonInit();
	p->_age = 1;

	return 0;
}

This will cause the runtime to crash, dereferencing the contents of the null pointer.

Let's look at it next:

class Person
{
public:
	void PersonInit()
	{
		cout << _age << endl;
	}

//private:
	int _age;		//声明
	char _name[20];
};

int main()
{
	Person* p = nullptr; //初始化为空指针
	p->PersonInit();

	return 0;
}

Here, when the Init function is called, a dereference is generated in the function, but this is a null pointer, and it will crash here.

Null pointers don't compile errors, they just crash.

Guess you like

Origin blog.csdn.net/Ljy_cx_21_4_3/article/details/132008758