[C++ Notes Summary] Object-Oriented Programming - Encapsulation|C++


foreword

This article starts a series aimed at summarizing all C++ notes before the autumn recruitment.
Reference answer: chatgpt

1. Class encapsulation

1.1, public, private, protected

The data in a class are called data members , and the functions in a class are called member functions .
In C++, member variables and member functions of a class can be restricted by access control characters, which are public (public), protected (protected) and private (private) . Example 1.1 is as follows:

#include <iostream>

class MyClass {
    
    
public:
    void setData(int shuru) {
    
    
        privateData = shuru; // 类内使用私有成员:将参数赋值给私有成员
        protectedData = shuru * 2; // 类内使用保护成员:将参数的两倍赋值给保护成员
        std::cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << std::endl;
        // 在类的成员函数中访问保护成员和私有成员
        privateFunc();
        protectedFunc();
    }
    int getData() {
    
    
        return privateData; // 类内使用私有成员::直接使用私有成员的名称
    }

protected:
    int protectedData; // 保护成员
    void protectedFunc() {
    
    
        std::cout << "This is a protected function." << std::endl;
    } // 保护成员函数

private:
    int privateData; // 私有成员
    void privateFunc() {
    
    
        std::cout << "This is a private function." << std::endl;
    } // 私有成员函数
};

int main() {
    
    
    MyClass obj;//对象
    obj.setData(1234);//公有方法,可以在类外访问
    std::cout << "Data: " << obj.getData() << std::endl; 公有方法,可以在类外访问

    // obj.privateData = 456; // 私有成员不能在类的外部访问
    // obj.privateFunc(); // 私有函数不能在类的外部访问
    // obj.protectedData = 789; // 不能在类的外部访问保护成员
    // obj.protectedFunc(); // 保护函数不能在类的外部访问

    return 0;
}

1) Public member functions can be accessed outside the class, which is equivalent to the external interface of the class. ; Private member functions and protected member functions cannot be accessed outside the class.
2) The difference between private members and protected members is that private members can only be accessed in member functions of the current class, and protected members can be accessed in member functions of the current class and member functions of derived classes.
3) Public member functions can access all members of the class, and private member functions and protected member functions can also access all members of the class.

1.2, class definition and class implementation are separated

In large C++ project files, class definition and implementation are often separated like this: (The following is divided into three files)
MyClass.h:

MyClass.h:
#ifndef MYCLASS_H
#define MYCLASS_H

class MyClass {
    
    
public:
    void setData(int shuru);
    int getData();

protected:
    int protectedData;
    void protectedFunc();

private:
    int privateData;
    void privateFunc();
};

#endif

If you use #include "myheader.h" multiple times in a source file, then this header file will be included multiple times.
If a header file is included multiple times, there will be a problem of duplicate definitions, resulting in compilation errors. In order to avoid this kind of problem, conditional compilation instructions, such as #ifndef and #define, are usually added at the beginning of the header file to prevent repeated inclusion of the header file. This ensures that the header file will only be included once, avoiding the problem of repeated definitions.

MYCLASS_H is a header file naming rule, usually used to prevent repeated inclusion of the same header file in the same file. This naming convention consists of the following steps:

Convert header file names to uppercase, eg myclass.h becomes MYCLASS.H.

Prepend an underscore to the file name, eg MYCLASS.H becomes _MYCLASS.H.

Add a macro definition after the file name, eg _MYCLASS.H becomes _MYCLASS_H.

This naming rule can effectively avoid repeated inclusion of the same header file in the same file, and can also make the name of the header file clearer and easier to understand. Of course, this naming rule is not mandatory, you can name the header file according to your own needs.

_MYCLASS.H, _MYCLASS_H and other header files can have many naming rules, but as long as they are consistent in the same project. In this way, the conflict of header files with the same name can be avoided, and it is also convenient for project maintenance and management. Usually, members of the team agree on a set of naming rules, which are then used uniformly throughout the project. This makes the code more standardized and easier to maintain.

MyClass.cpp:

MyClass.cpp:
#include "MyClass.h"
#include <iostream>

void MyClass::setData(int shuru) {
    
    
    privateData = shuru; // 类内使用私有成员:将参数赋值给私有成员
    protectedData = shuru * 2; // 类内使用保护成员:将参数的两倍赋值给保护成员
    std::cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << std::endl;
    // 在类的成员函数中访问保护成员和私有成员
    privateFunc();
    protectedFunc();
}

int MyClass::getData() {
    
    
    return privateData; // 类内使用私有成员::直接使用私有成员的名称
}

void MyClass::protectedFunc() {
    
    
    std::cout << "This is a protected function." << std::endl;
} // 保护成员函数

void MyClass::privateFunc() {
    
    
    std::cout << "This is a private function." << std::endl;
} // 私有成员函数

main.cpp:

main.cpp:
#include <iostream>
#include "MyClass.h"

int main() {
    
    
    MyClass obj;
    obj.setData(1234);
    std::cout << "Data: " << obj.getData() << std::endl;

    // obj.privateData = 456; // 私有成员不能在类的外部访问
    // obj.privateFunc(); // 私有函数不能在类的外部访问
    // obj.protectedData = 789; // 不能在类的外部访问保护成员
    // obj.protectedFunc(); // 保护函数不能在类的外部访问

    return 0;
}

There are many benefits of doing this:
1) Make the code clearer and easier to maintain. The interface and implementation of the class are separated, which can more clearly distinguish which are public interfaces and which are implementation details, which is convenient for users and developers to understand and use.
2) Improve code reusability. Separating the implementation of the class from the interface makes it easy to reuse the implementation part of the class in other projects without worrying about conflicts and problems that may be introduced.
3) Increase code security. Hiding the implementation details of the class can prevent external code from directly accessing the private data and private methods of the class, thereby improving the security of the code.
4) Reduce the coupling of code. The separation of class interface and implementation can decouple the implementation part of the class from other codes, thereby reducing the coupling degree of the code and improving the maintainability and scalability of the code.

In the terminal, the following command can be used to execute: Compile the MyClass.cpp file into an object file, and link it together with the main.cpp file into an executable file to run the program correctly.

g++ -c MyClass.cpp -o MyClass.o 
g++ main.cpp MyClass.o -o main
./main.exe

Of course, this is relatively simple, and it is more complicated to use Cmake

1.3, constructor, destructor, copy constructor

Constructors and destructors are special member functions in C++ that are called when an object is constructed and destructed, respectively.
The main function of the constructor is to initialize the member variables of the object and provide a reasonable initial state for the object. When we create an object, the compiler will automatically call the object's constructor. If we don't define a constructor, the compiler generates a default constructor , which does nothing. But if we need to perform some initialization operations when the object is created, we need to define our own constructor.
The main function of the destructor is to release resources when the object is destroyed, such as closing files, releasing memory, and so on. When an object is destroyed, the compiler automatically calls the object's destructor. If we don't define a destructor, the compiler generates a default destructor , which does nothing. But if we need to perform some cleanup operations when the object is destroyed, we need to define our own destructor.
In short, the constructor and destructor are very important special member functions in C++. They are called when the object is constructed and destroyed respectively, and are used to initialize the member variables of the object and release the resources occupied by the object.

Example 1.1 adds constructor and destructor to get Example 1.2. You can feel the function of constructor and destructor:

#include <iostream>
using namespace std;

class MyClass {
    
    
public:
    MyClass(int data) : privateData(data) {
    
    
        protectedData = data * 2;//初始化变量
        cout << "MyClass constructor called." << endl;
    }

    ~MyClass() {
    
    
        cout << "MyClass destructor called." << endl;
    }

    void setData(int shuru) {
    
    
        privateData = shuru;
        protectedData = shuru * 2;
        cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << endl;
        privateFunc();
        protectedFunc();
    }

    int getData() {
    
    
        return privateData;
    }

protected:
    int protectedData;
    void protectedFunc() {
    
    
        cout << "This is a protected function." << endl;
    }

private:
    int privateData;
    void privateFunc() {
    
    
        cout << "This is a private function." << endl;
    }
};

int main() {
    
    
    MyClass obj(100);
    obj.setData(12345);
    cout << "Data: " << obj.getData() << endl;

    return 0;
}

This is a constructor's initialization list for initializing the private member variable privateData. privateData(data) means to assign the incoming parameter data to the private member variable privateData. This method is more efficient than direct assignment in the function body of the constructor, because it avoids re-initialization of member variables in the constructor body.

Of course, in a class, there are more than one form of the constructor, the following is an example:

#include <iostream>
using namespace std;

class MyClass {
    
    
public:
    MyClass() : privateData(0), protectedData(0) {
    
    
        cout << "MyClass default constructor called." << endl;
    }

    MyClass(int data) : privateData(data) {
    
    
        protectedData = data * 2;
        cout << "MyClass constructor with one parameter called." << endl;
    }

    MyClass(int data1, int data2) : privateData(data1), protectedData(data2) {
    
    
        cout << "MyClass constructor with two parameters called." << endl;
    }

    ~MyClass() {
    
    
        cout << "MyClass destructor called." << endl;
    }

    void setData(int shuru) {
    
    
        privateData = shuru;
        protectedData = shuru * 2;
        cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << endl;
        privateFunc();
        protectedFunc();
    }

    int getData() {
    
    
        return privateData;
    }

protected:
    int protectedData;
    void protectedFunc() {
    
    
        cout << "This is a protected function." << endl;
    }

private:
    int privateData;
    void privateFunc() {
    
    
        cout << "This is a private function." << endl;
    }
};

int main() {
    
    
    MyClass obj1;
    MyClass obj2(100);
    MyClass obj3(100, 200);
    obj2.setData(12345);
    cout << "Data: " << obj2.getData() << endl;

    return 0;
}

In this code, we added a default constructor MyClass(), a constructor MyClass(int data) with one parameter, and a constructor MyClass(int data1, int data2) with two parameters. At the same time, we also modified the output information of the constructor to distinguish them better.
Output result:
insert image description here

The relationship between constructors and destructors:

Constructors and destructors come in pairs, constructors are used to initialize objects, and destructors are used to clean up objects. The constructor is called once when the object is created, and the destructor is called once when the object is destroyed. Therefore, they are in one-to-one correspondence.
In a program, the number of constructor and destructor calls depends on the creation and destruction of objects. If only one object is created, the constructor and destructor are each called once. If multiple objects are created, the constructor and destructor are called once for each object. If objects are created on the stack, their constructors and destructors are called when entering and leaving scope. If the object is created on the heap, you need to manually call delete to destroy the object, then the destructor will be called.
It should be noted that if a class inherits another class, then when creating and destroying objects, the order of calling constructors and destructors is from the base class to the derived class. That is to say, the constructor of the base class is called first, and then the constructor of the derived class is called; the destructor of the derived class is called first, and then the destructor of the base class is called.

In addition, there is a special constructor: Copy constructor :
A copy constructor is a special constructor used to copy the value of one object to another object. The role of the copy constructor is to create a new object and copy the values ​​​​of the existing object into the new object. It is commonly used in the following three situations:
1) Initialize a new object with an existing object.
2) Pass an object as a parameter to a function.
3) Return an object in the function.
for example:

#include <iostream>
using namespace std;

class MyClass {
    
    
public:
    MyClass() : privateData(0), protectedData(0) {
    
    
        cout << "MyClass default constructor called." << endl;
    }

    MyClass(int data) : privateData(data) {
    
    
        protectedData = data * 2;
        cout << "MyClass constructor with one parameter called." << endl;
    }

    MyClass(int data1, int data2) : privateData(data1), protectedData(data2) {
    
    
        cout << "MyClass constructor with two parameters called." << endl;
    }

    MyClass(const MyClass& other) {
    
    
        privateData = other.privateData;
        protectedData = other.protectedData;
        cout << "MyClass copy constructor called." << endl;
    }

    ~MyClass() {
    
    
        cout << "MyClass destructor called." << endl;
    }

    void setData(int shuru) {
    
    
        privateData = shuru;
        protectedData = shuru * 2;
        cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << endl;
        privateFunc();
        protectedFunc();
    }
       int getData() {
    
    
        return privateData;
    }

protected:
    int protectedData;
    void protectedFunc() {
    
    
        cout << "This is a protected function." << endl;
    }

private:
    int privateData;
    void privateFunc() {
    
    
        cout << "This is a private function." << endl;
    }
};

void func1(MyClass obj) {
    
    
    cout << "func1 called." << endl;
}

MyClass func2() {
    
    
    cout << "func2 called." << endl;
    MyClass obj(456);
    return obj;
}

int main() {
    
    
    MyClass obj1;
    MyClass obj2(100);
    MyClass obj3(100, 200);
    obj2.setData(12345);
    cout << "Data: " << obj2.getData() << endl;

    MyClass obj4(obj2);
    MyClass obj5 = obj3;

    func1(obj4);
    MyClass obj6 = func2();

    return 0;
}

Here a copy constructor is added to copy the value of one object into another object. At the same time, I added two functions, one that passes an object as an argument to the function, and one that returns the object within the function. Both functions automatically call the copy constructor.
In the main function, I create several objects and call their member functions. Then, I create two new objects, one through the copy constructor and the other through the assignment operator. In the end, I called two functions, one passing the object as an argument to the function, and the other returning the object within the function. In both functions, the copy constructor is called automatically.

insert image description here

In these cases, if no copy constructor is defined, the compiler will automatically generate a default copy constructor to complete the copying of the object. If you need to make a deep copy, you need to define the copy constructor yourself.

1.4, static data members and static member functions

A static data member is a member that belongs to a class, not a member of an object that belongs to the class. They are declared when the class is defined, not when objects of the class are created. They are shared by all objects of that class, so their values ​​are the same across all objects. Static data members are created at the beginning of the program and destroyed at the end of the program (instead of construction and destruction)

The existence of static data members has the following advantages:
Unlike ordinary member variables, static data members do not need to be stored in each object. This saves memory space.
Static data members can be shared by all objects of the class, which makes them useful for passing information between all objects of the class.
Static data members can be accessed outside the class, which allows them to be used to implement functions similar to global variables.
Static data members can be used as constant expressions, which makes them useful for computing constant values ​​at compile time.

A static member function is a member function decorated with the static keyword in a class. Static member functions do not depend on any object and can be called directly through the class name without creating an object. Therefore, static member functions cannot access non-static member variables and non-static member functions, only static member variables and static member functions.

(example):

#include <iostream>
using namespace std;

class MyClass {
    
    
public:
    MyClass() : privateData(0), protectedData(0) {
    
    
        cout << "MyClass default constructor called." << endl;
        count++; // 每次创建对象时,对象数量加1
    }

    MyClass(int data) : privateData(data) {
    
    
        protectedData = data * 2;
        cout << "MyClass constructor with one parameter called." << endl;
        count++; // 每次创建对象时,对象数量加1
    }

    MyClass(int data1, int data2) : privateData(data1), protectedData(data2) {
    
    
        cout << "MyClass constructor with two parameters called." << endl;
        count++; // 每次创建对象时,对象数量加1
    }

    MyClass(const MyClass& other) {
    
    
        privateData = other.privateData;
        protectedData = other.protectedData;
        cout << "MyClass copy constructor called." << endl;
        count++; // 每次创建对象时,对象数量加1
    }

    ~MyClass() {
    
    
        cout << "MyClass destructor called." << endl;
        count--; // 每次销毁对象时,对象数量减1
    }

    void setData(int shuru) {
    
    
        privateData = shuru;
        protectedData = shuru * 2;
        cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << endl;
        privateFunc();
        protectedFunc();
    }
    
    int getData() {
    
    
        return privateData;
    }

    static int getCount() {
    
    
        return count; // 返回对象数量
    }

protected:
    int protectedData;
    void protectedFunc() {
    
    
        cout << "This is a protected function." << endl;
    }

private:
    int privateData;
    void privateFunc() {
    
    
        cout << "This is a private function." << endl;
    }

    static int count; // 所有对象的数量
};

int MyClass::count = 0; // 在类外部初始化静态数据成员

void func1(MyClass obj) {
    
    
    cout << "func1 called." << endl;
}

MyClass func2() {
    
    
    cout << "func2 called." << endl;
    MyClass obj(456);
    return obj;
}

int main() {
    
    
    MyClass obj1;
    MyClass obj2(100);
    MyClass obj3(100, 200);
    obj2.setData(12345);
    cout << "Data: " << obj2.getData() << endl;

    MyClass obj4(obj2);
    MyClass obj5 = obj3;

    cout << "Total objects: " << MyClass::getCount() << endl; // 输出对象数量

    func1(obj4);
    MyClass obj6 = func2();

    cout << "Total objects: " << MyClass::getCount() << endl; // 输出对象数量

    return 0;
}

Static members are often used for counter functions, as shown in the above code.
Of course, static data members can be referenced by objects. For example, MyClass::getCount() is actually similar to obj6.getCount(), but: MyClass::
getCount() is a static call, no need to create an object, and can be called anywhere ;

obj6.getCount() is a dynamic call, you need to create an object first, and then call it through the object name.

Another thing to note is that static member functions can only access static member variables and static member functions, but not non-static member variables and non-static member functions. Therefore, if you need to access non-static member variables or non-static member functions, you need to call the member function through the object name.

1.5, friend function, friend class

A friend is a special concept in the C++ language that allows a function or class to access protected and private members of another class . Encapsulation in C++ requires that private and protected members of a class can only be accessed by member functions of the class, while the friend mechanism breaks this restriction, allowing some external functions or classes to access private and protected members, thereby improving program flexibility and scalability.

Friend functions can be placed anywhere in the class, and the implementation part is placed outside the class.

A friend class means that one class can access the private members and protected members of another class, and this class is the friend class of another class. The declaration method of a friend class is similar to that of a friend function, and it needs to be declared with the friend keyword in the class declaration.
A friend class can access the private members and protected members of the class it declares, but it is not itself a member of the class it declares, so it cannot directly access the member variables and member functions of the class it declares. If you need to access the member variables and member functions of the class it declares, you can access it through the class object or pointer.

Below is an example:

#include <iostream>
using namespace std;

class MyClass {
    
    
public:
    MyClass() : privateData(0), protectedData(0) {
    
    
        cout << "MyClass default constructor called." << endl;
        count++; // 每次创建对象时,对象数量加1
    }

    MyClass(int data) : privateData(data) {
    
    
        protectedData = data * 2;
        cout << "MyClass constructor with one parameter called." << endl;
        count++; // 每次创建对象时,对象数量加1
    }

    MyClass(int data1, int data2) : privateData(data1), protectedData(data2) {
    
    
        cout << "MyClass constructor with two parameters called." << endl;
        count++; // 每次创建对象时,对象数量加1
    }

    MyClass(const MyClass& other) {
    
    
        privateData = other.privateData;
        protectedData = other.protectedData;
        cout << "MyClass copy constructor called." << endl;
        count++; // 每次创建对象时,对象数量加1
    }

    ~MyClass() {
    
    
        cout << "MyClass destructor called." << endl;
        count--; // 每次销毁对象时,对象数量减1
    }

    void setData(int shuru) {
    
    
        privateData = shuru;
        protectedData = shuru * 2;
        cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << endl;
        privateFunc();
        protectedFunc();
    }
    
    int getData() {
    
    
        return privateData;
    }

    static int getCount() {
    
    
        return count; // 返回对象数量
    }

protected:
    int protectedData;
    void protectedFunc() {
    
    
        cout << "This is a protected function." << endl;
    }

private:
    int privateData;
    void privateFunc() {
    
    
        cout << "This is a private function." << endl;
    }

    static int count; // 所有对象的数量

    friend void friendFunc(MyClass obj); // 声明友元函数
    friend class FriendClass; // 声明友元类,FriendClass是Myclass的友元类
};

int MyClass::count = 0; // 在类外部初始化静态数据成员

void friendFunc(MyClass obj) {
    
     // 定义友元函数
    cout << "friendFunc called, privateData = " << obj.privateData << endl;
    obj.privateFunc();
}

class FriendClass {
    
     // 定义友元类
public:
    void friendClassFunc(MyClass obj) {
    
    
        cout << "FriendClass called, protectedData = " << obj.protectedData << endl;
        obj.protectedFunc();
    }
};

void func1(MyClass obj) {
    
    
    cout << "func1 called." << endl;
    friendFunc(obj); // 调用友元函数
}
MyClass func2() {
    
    
    cout << "func2 called." << endl;
    MyClass obj(456);
    return obj;
}
int main() {
    
    
    MyClass obj1;
    MyClass obj2(100);
    MyClass obj3(100, 200);
    obj2.setData(12345);
    cout << "Data: " << obj2.getData() << endl;
    MyClass obj4(obj2);
    MyClass obj5 = obj3;

    cout << "Total objects: " << MyClass::getCount() << endl; // 输出对象数量

    func1(obj4);

    FriendClass friendObj; // 创建友元类对象
    friendObj.friendClassFunc(obj2); // 调用友元类的成员函数

    MyClass obj6 = func2();

    cout << "Total objects: " << MyClass::getCount() << endl; // 输出对象数量

    return 0;

}

The disadvantages of friends mainly include the following points:
Destruction of encapsulation: Friends can access the private members and protected members of the class, which destroys the encapsulation and may reduce the security of the class.

It may lead to increased coupling: friend functions or friend classes need to know the implementation details of the class, which may lead to an increase in the coupling between the class and the friend, making the implementation of the class more complicated.

Friend does not have inheritance: If a class is a friend of another class, then it does not have inheritance, that is, it cannot access private and protected members of derived classes.
Therefore, careful consideration is required when using friends, and friends should only be used when necessary.

Second, the implementation of the class - object

2.1, Static allocation of objects, dynamic allocation (heap objects)

The static allocation and dynamic allocation of object memory refer to whether the memory space occupied by the object is determined at compile time or dynamically allocated at runtime when the program is running.
Static allocation refers to the allocation of fixed-size memory space for objects at compile time, which is also called stack allocation . The stack is a first-in, last-out data structure. Its memory allocation and release are automatically completed by the system, and programmers do not need to manually manage memory. The advantage of static allocation is fast speed, but the disadvantage is that the memory space is fixed, not flexible enough, and cannot be dynamically expanded.
Dynamic allocation refers to the dynamic allocation of memory space according to the needs when the program is running. This method is also called heap allocation . The heap is a way to dynamically allocate memory, and programmers need to manually manage the allocation and release of memory. The advantage of dynamic allocation is that it is flexible and can dynamically expand the memory space. The disadvantage is that it is slow and prone to problems such as memory leaks and memory fragmentation.
For object memory allocation, it is generally recommended to use dynamic allocation , especially when the size of the object is uncertain or when dynamic expansion is required. But in some cases, static allocation is also a good choice. For example, when the size of the object is fixed and small, or objects need to be created and destroyed frequently, using static allocation can improve the running efficiency of the program.

Statically allocated objects are also called automatic variables, stack variables, or local variables . Their memory has been allocated when the program is compiled, and the scope is only in the current code block. When the code block is executed, they will be automatically destroyed.
A dynamically allocated object is also called a heap object, a dynamic object, or a dynamically allocated object . Their memory space is dynamically allocated when the program is running, and the scope can span multiple code blocks, requiring manual management of memory allocation and release.

The following is an example of creating and deleting a heap object and creating and deleting an array of heap objects

#include <iostream>
using namespace std;

class MyClass
{
    
    
public:
    MyClass() {
    
     cout << "MyClass constructed!" << endl; }
    ~MyClass() {
    
     cout << "MyClass destructed!" << endl; }
};

int main()
{
    
    
    // 建立堆对象
    MyClass* ptr = new MyClass();
    // 使用堆对象
    cout << "Using heap object..." << endl;
    // 删除堆对象
    delete ptr;
    return 0;
}
#include <iostream>
using namespace std;

class MyClass
{
    
    
public:
    MyClass() {
    
     cout << "MyClass constructed!" << endl; }
    ~MyClass() {
    
     cout << "MyClass destructed!" << endl; }
};

int main()
{
    
    
    // 建立堆对象数组
    MyClass* arr = new MyClass[5];
    // 使用堆对象数组
    cout << "Using heap object array..." << endl;
    // 删除堆对象数组
    delete[] arr;
    return 0;
}

2.2, child object

2.3, this pointer

The this pointer is a pointer to the current object, which is used in member functions. The function of this pointer is to distinguish member variables and local variables with the same name. In a member function, if there is a parameter with the same name as a member variable, when the variable name is used directly in the function, the compiler will use the parameter instead of the member variable by default. At this time, you can use the this pointer to clearly indicate that you want to use member variables instead of parameters.
In addition, the this pointer can also be used to return a reference to the current object in a member function. For example, you can return *this in a member function, which means returning a reference to the current object. This is very common in chaining calls and can make the code more concise and readable.

for example:

#include <iostream>
using namespace std;

class Person {
    
    
public:
    int age;
    int getAge() {
    
    
        return this->age;
    }
};

int main() {
    
    
    Person person1;
    person1.age = 18;
    cout << "person1's age is " << person1.getAge() << endl;

    Person person2;
    person2.age = 25;
    cout << "person2's age is " << person2.getAge() << endl;

    return 0;
}

The above is equivalent to the following:

```cpp
#include <iostream>
using namespace std;

class Person {
    
    
public:
    int age;
    int getAge() {
    
    
        return age;
    }
};

int main() {
    
    
    Person person1;
    person1.age = 18;
    cout << "person1's age is " << person1.getAge() << endl;

    Person person2;
    person2.age = 25;
    cout << "person2's age is " << person2.getAge() << endl;

    return 0;
}

In a member function, you can directly access the member variables of the class without using the "this" pointer. Therefore, "return this->age" and "return age" are equivalent. However, using the "this" pointer can clearly represent the current object and increase the readability of the code.

Guess you like

Origin blog.csdn.net/weixin_46274756/article/details/131020776