0 Basics Introduction to C++ and Objects Part 1

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

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.

insert image description here

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

insert image description here

2. Introduction of class

In the previous study of C language, we defined the structure like this:
Please add a picture description
But the structure in C language can only define variables.

In C++, not only variables can be defined in the structure, but also functions can be defined . For example: in the data structure, the stack implemented in C language can only define variables in the structure ; now it is implemented in C++, you will find that functions can also be defined in the struct . Please add a picture description
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 content in the class body is called the members of the class : the variables in the class are called the attributes or member variables of the class ; the functions in the class are called the methods or member functions of the class .

3.1 Two ways to define a class:

  1. The declaration and definition are all placed in the class body. Note: If the member function is defined in the class , the compiler may treat it as an inline function .
    Please add a picture description
  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::
    Please add a picture description

3.2 Suggestions for member variable naming rules

Here is such a class

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

Date has a member variable (attribute) year, and then there is a member function Init, but the formal parameter of the Init function has the same name as the member variable, so there is a problem here, is the year in Init a member variable or a function parameter?
insert image description here
In the above figure, we observed through debugging that the member variable year of d1 has not been really initialized. Therefore, both years in Init are formal parameters.

In this regard, we give the following suggestions for naming member variables:

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

We can add a _ and a formal parameter in front of the member variable to distinguish (of course, which method to choose to distinguish depends on your preference).

insert image description here

4. Class access qualifiers and encapsulation

We directly replace the struct of the stack written above with the structure struct into a class

insert image description here
insert image description here
At this point we found that the program reported an error: the function is not accessible, what's going on?

This is the class access qualifier in C++ we are going to understand next .

4.1 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 provide its interface to external users through access rights.

insert image description here

Access Qualifier Description

  1. The default access permission of class is private, and struct is public (because struct is compatible with C)

This is also the reason why the error was reported when it was changed to Class just now.
insert image description here

  1. Publicly 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)

At this stage, we are just starting to learn and don't consider the difference between the two

  1. Access scopes start at the occurrence of this access qualifier until the next occurrence of the access qualifier

Here is the quote

  1. If there is no access qualifier behind, the scope will go to }, which is the end of the class.

insert image description here
So let's think about a 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 definition class, the difference is that the default access right of class defined by struct is public, and the default access right of class defined by class is private. Note: There are also differences between struct and class in the position of inheritance and template parameter list, which will be introduced later.

4.2 Packaging

Object-oriented three major features: encapsulation, inheritance, polymorphism .

In the class and object stage, the main research is on the encapsulation characteristics of the class, so what is encapsulation?

Encapsulation: organically combine the data and the method of manipulating the 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, making it easier for users to use classes. **For example: For a complex device such as a computer, the only thing provided to the user is the power button, keyboard input, monitor, USB jack, etc., allowing the user to interact with the computer and complete daily affairs. But in fact, the real work of the computer is some hardware components such as CPU, graphics card, and memory.
insert image description here
For computer users, they don’t need to care about internal core components, such as how the circuits on the motherboard are laid out, how the CPU is designed inside, 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 the computer manufacturer leaves the factory, it puts a shell on the outside to hide the internal implementation details, and only provides external switches, mouse and keyboard jacks, etc., so that users can interact with the computer.

Encapsulation in the C++ language can organically combine data and methods of manipulating data through classes, hide internal implementation details of objects through access rights, and control which methods can be used directly outside the class.

5. Class scope

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.Please add a picture description

6. Class instantiation

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

  1. A class is a description of an object . It is a model -like thing, which defines which members a class has, and defines a class without allocating actual memory space to store it; for example: the student information form filled out during enrollment, the form can be Think of it as a class to describe specific student information.

    The class is like a riddle, describing the answer, and the answer is an instance of the riddle.

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

insert image description here

7. Class object model

7.1 How to calculate the size of a class object

Now there is such a class:

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

Then everyone thinks about a question:
a class can have both member variables and member functions, so what is contained in a class object? How to calculate the size of a class?

7.2 Guessing the storage method of class objects

We assume the following possibilities:

  1. The object contains each member of the class, and the member variables and functions are stored in the object.
    insert image description here
    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 , a copy of the code is saved in each object, and the same code is saved multiple times, wasting space. So how to solve it?

  2. Only one copy of the member function is saved, and the address of the storage function is saved in the object

insert image description here

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

insert image description here
So for the above three storage methods, which method does the computer store in?

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;
	Date d2;

	cout << sizeof(d1) <<endl;
	cout << sizeof(d2) <<endl;

	return 0;
}

insert image description here
From the results in the figure above, we know that the correct storage method is the third one: only member variables are stored in class objects, and member functions are not stored (nor are addresses), and member functions are stored in public code segments.

Conclusion: The size of a class is actually the sum of the "member variables" in the class. Of course, 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.

8. this pointer

8.1 Derivation of this pointer

Let's define a date class first:

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;
};

We now create two objects of this class and call member functions:

int main()
{
    
    
	Date d1;
	Date d2;
	d1.Init(2023,9,5);
	d2.Init(2023,8,18);
	d1.Print();
	d2.Print();

	return 0;
}

insert image description here
We see that the properties (member variables) of d1 and d2 can be initialized and printed correctly.

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

In this regard, 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", so that the pointer points to the current object (the object that calls the function when the function is running) ), all operations of "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.

8.2 Characteristics of this pointer

  1. The type of this pointer: the type of the class * const, that is, in member functions, the this pointer cannot be assigned a value.

For example, in the Date class above, the type of this pointer is Date* const

  1. Can only be used inside a "member function"
  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 as an actual parameter to this formal parameter. So 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 Comparison between C language and C++ to realize Stack

//C语言实现
typedef int DataType;
typedef struct Stack
{
    
    
    DataType* array;
    int capacity;
    int size;
}Stack;
void StackInit(Stack* ps)
{
    
    
    assert(ps);
    ps->array = (DataType*)malloc(sizeof(DataType) * 3);
    if (NULL == ps->array)
    {
    
    
        assert(0);
        return; 
    }

      ps->capacity = 3;
      ps->size = 0;
}
void StackDestroy(Stack* ps)
{
    
    
    assert(ps);
    if (ps->array)
    {
    
    
        free(ps->array);
        ps->array = NULL;
        ps->capacity = 0;
        ps->size = 0;
    } 
}
void CheckCapacity(Stack* ps)
{
    
    
    if (ps->size == ps->capacity)
    {
    
    
        int newcapacity = ps->capacity * 2;
        DataType* temp = (DataType*)realloc(ps->array,
        newcapacity*sizeof(DataType));
        if (temp == NULL)
        {
    
    
            perror("realloc申请空间失败!!!");
            return; 
        }
        ps->array = temp;
        ps->capacity = newcapacity;
    }
}
void StackPush(Stack* ps, DataType data)
{
    
    
    assert(ps);
    CheckCapacity(ps);
    ps->array[ps->size] = data;
    ps->size++;
}
int StackEmpty(Stack* ps)
{
    
    
    assert(ps);
    return 0 == ps->size;
}
void StackPop(Stack* ps)
{
    
    
    if (StackEmpty(ps))
        return;
    ps->size--;
}
DataType StackTop(Stack* ps)
{
    
    
    assert(!StackEmpty(ps));
    return ps->array[ps->size - 1];
}
int StackSize(Stack* ps)
{
    
    
    assert(ps);
    return ps->size;
}
int main() 
{
    
    
    Stack s;
    StackInit(&s);
    StackPush(&s, 1);
    StackPush(&s, 2);
    StackPush(&s, 3);
    StackPush(&s, 4);
    printf("%d\n", StackTop(&s));
    printf("%d\n", StackSize(&s));
    StackPop(&s);
    StackPop(&s);
    printf("%d\n", StackTop(&s));
    printf("%d\n", StackSize(&s));
    StackDestroy(&s);
    return 0; 
}

It can be seen that when implemented in C language, Stack-related operation functions have the following commonality: the
first parameter of each function
must be checked for the first parameter in the Stack* function, because the parameter may be a NULL
function In all of them, the Stack* parameter is used to operate the stack.
The address of the Stack structure variable must be passed when calling.

Only the structure for storing data can be defined in the structure, and the method of operating data cannot be placed in the structure, that is, the data and the way of operating data are separated , and the implementation is quite complicated, involving a large number of pointer operations, so pay attention It might go wrong.

//C++实现
typedef int DataType;
class Stack
{
    
    
   public:
void Init() 
{
    
    
      _array = (DataType*)malloc(sizeof(DataType) * 3);
      if (NULL == _array)
       {
    
    
          perror("malloc申请空间失败!!!");
          return; 
       }
        _capacity = 3;
        _size = 0; 
}
void Push(DataType data)
{
    
    
        CheckCapacity();
        _array[_size] = data;
        _size++;
}
void Pop() 
{
    
    
   if (Empty())
       return;
   _size--; 
}
    DataType Top()
    {
    
     
       return _array[_size - 1];
    }
    int Empty() {
    
     return 0 == _size;}
    int Size(){
    
     return _size;}
    void Destroy()
    {
    
    
         if (_array) 
         {
    
    
            free(_array);
            _array = NULL;
            _capacity = 0;
            _size = 0;
         } 
     }
private:
    void CheckCapacity()
    {
    
    
        if (_size == _capacity)
        {
    
    
            int newcapacity = _capacity * 2;
            DataType* temp = (DataType*)realloc(_array, newcapacity *
sizeof(DataType));
            if (temp == NULL)
            {
    
    
               perror("realloc申请空间失败!!!");
               return; 
            }
            _array = temp;
            _capacity = newcapacity;
        }
     } 
private:
    DataType* _array;
    int _capacity;
    int _size;
};
int main() 
{
    
    
    Stack s;
    s.Init();
    s.Push(1);
    s.Push(2);
    s.Push(3);
    s.Push(4);
    printf("%d\n", s.Top());
    printf("%d\n", s.Size());
    s.Pop();
    s.Pop();
    printf("%d\n", s.Top());
    printf("%d\n", s.Size());
    s.Destroy();
    return 0; 
}

In C++, the data and the methods of manipulating the data can be perfectly combined through the class, and those methods that can be called outside the class can be controlled through the access authority, that is, encapsulation . cognition of things. Moreover, each method does not need to pass the Stack* parameter, and the parameter will be automatically restored after the compiler compiles, that is, the Stack * parameter in C++ is maintained by the compiler, but in C language, it needs to be maintained by the user.

Guess you like

Origin blog.csdn.net/weixin_69423932/article/details/132355870