[C + + from 0 to 1] Part 3: classes and objects

Posted by Aleks on Wed, 19 Jan 2022 11:20:07 +0100

1, Preliminary understanding of process oriented and object oriented

C language is process oriented, focusing on the process, analyzing the steps of solving the problem, and gradually solving the problem through function call.
C + + is based on object-oriented and focuses on objects. It divides a thing into different objects and completes it by the interaction between objects.

2, Class introduction

First, let's look at the simplest class:

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

You can also call print:

For the definition of the above structure, class is preferred in C + +

3, Class definition

class className
{
// Class body: composed of member functions and member variables
}; // Be sure to pay attention to the semicolon

Class is the keyword that defines the class, ClassName is the name of the class, and {} is the body of the class. Note that the semicolon is followed at the end of class definition.
The elements in a class are called class members: the data in a class is called class attributes or member variables; Functions in a class are called methods or member functions of the class.
Two ways to define classes
Class can be defined in two ways:

  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.
  2. The statement is placed in the h file, the class definition is placed in cpp file

Generally, the second method is more desirable.

4, Access qualifier and encapsulation of class

4.1 access qualifier

C + + implementation of encapsulation: combine the attributes and methods of the object with classes to make the object more perfect, and selectively provide its interface to external users through access rights.

Access qualifier description

  1. Members decorated with public can be accessed directly outside the class
  2. Protected and private modified members cannot be accessed directly outside the class (protected and private are similar here)
  3. The scope of access rights starts from where the access qualifier appears until the next access qualifier appears
  4. The default access permission of class is private and struct is public (because struct is compatible with C)

Change struct to class: external can not be accessed directly.


Add public:

4.2 packaging

5, Scope of class

Class defines a new scope, and all members of the class are in the scope of the class. To define a member outside a class, you need to use the:: scope resolver to indicate which class domain the member belongs to.

class Person
{
public:
	void PrintPersonInfo();

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

// Here, you need to specify that PrintPersonInfo belongs to the Person class field
void Person::PrintPersonInfo()
{
	cout << _name << _gender << _age << endl;
}

6, Class instantiation

The process of creating objects with class types is called class instantiation

  1. A class is just a model that defines which members a class has and defines that 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. For example. Class instantiation of objects is like building a house using architectural design drawings in reality. Class is like design drawings. It only designs what is needed, but there is no physical building. Similarly, class is only a design. The instantiated objects can actually store data and occupy physical space.


7, Class object model

7.1 how to calculate the size of class objects

#include <iostream>
#include <string.h>
using namespace std;

class Person
{
public:
	void PrintPersonInfo();

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

// Here, you need to specify that PrintPersonInfo belongs to the Person class field
void Person::PrintPersonInfo()
{
	cout << _name << _gender << _age << endl;
}

int main()
{
	Person p1;
	cout << sizeof(p1) << " " << sizeof(Person) << endl;//What's the size?
	return 0;
}


The size of the Person class calculated here is obviously the size of all member variables in the class (_name,_gender,_age)

7.2 storage method of class objects

Only member variables are saved, and member functions are stored in public code segments


Conclusion: the size of a class is actually the sum of "member variables" in the class. Of course, memory alignment should also be carried out. Pay attention to the size of empty classes. Empty classes are special. The compiler gives empty classes a byte to uniquely identify this class.

#include <iostream>
#include <string.h>
using namespace std;

class A
{
public:
	void F()
	{
		//
	}

private:
	int _a;

};

class B
{
public:
	void F()
	{
		//
	}
};

class C
{
    
};

int main()
{
	cout << sizeof(A) << endl;//How much output
	cout << sizeof(B) << endl;//How much output
	cout << sizeof(C) << endl;//How much output
	return 0;
}


Note: the size of the empty class is 1, which plays the role of a station.

7.3 structure memory alignment rules

  1. The first member is at an address offset 0 from the structure.
  2. Other member variables should be aligned to the address of an integer multiple of a number (alignment number). (alignment number = the smaller value of the compiler's default alignment number 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 maximum of all variable types and the minimum of the default alignment parameter).
  4. If a structure is nested, the nested structure is aligned to an integer multiple of its 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).

8, this pointer

8.1 leading out of this pointer

Let's define a Date class Date first

#include <iostream>
#include <string.h>
using namespace std;

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

	void PrintDate()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

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



For the above classes, there is such a problem:
There are two member functions Init and PrintDate in the Date class. There is no distinction between different objects in the function body. When d1 calls Init function, how does the function know that d1 object should be set instead of d2 object?
Drawing demonstration:

This problem is solved by introducing this pointer in C + +, That is, the C + + compiler adds a hidden pointer parameter to each "non static member function" so that the pointer points to the current object (the object that calls the function when the function runs) , the operation of all member variables in the function body is accessed through this pointer. However, all operations are transparent to the user, that is, the user does not need to pass them, and the compiler completes them automatically.

8.2 characteristics of this pointer

1. When calling a member function, the parameter passed to this cannot be displayed.

2. When defining a member function, the declaration formal parameter this cannot be displayed.

3. Inside the member function, we can use this.

4. Type of this pointer: class type * const

5.this pointer is the first implicit pointer parameter of the member function. Generally, it is automatically passed by the compiler through the ecx register without user passing

Interview questions:

  1. Where does this pointer exist?
    Generally, it is on the stack (formal parameter), and some compilers will put it in registers (VS2019, which has been verified above).
  2. Can this pointer be null?
    We use an example to verify:
#include <iostream>
#include <string.h>
using namespace std;

// 1. Can the following program be compiled?
// 2. Will the following program crash? Where did it collapse
class A
{
public:
	void PrintA()
	{
		cout << _a << endl;
	}
	void Show()
	{
		cout << "Show()" << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	p->Show();
	p->PrintA();
}

To verify:


Why? We draw pictures to explain:

Topics: C++ Back-end