Pointer Literacy in C++

foreword

Pointers are a hurdle that must be overcome for those who learn C/C++, just like learning Jiuyang Shengong must open up the two veins of Ren and Du. Although it is said that with the popularity of smart pointers, programmers rarely need to manually manipulate raw pointers,
but if you don't even learn raw pointers well, how can you use smart pointers well?

Whether it is a raw pointer or a smart pointer, you must do it if you want to use it well 知其然,知其所以然.

Because the object of reading this article is children's shoes with a certain pointer foundation, if you are in a state of ignorance about pointers, it is recommended to review the basic knowledge of pointers first, otherwise reading may discourage your desire for knowledge.

Why do pointers have types?

It is for pointer arithmetic and value retrieval.

When using a pointer to get a value, you need to know how to get the value, such as how many bytes to get the value. This needs to be determined to get the correct value. To know how many bytes to get, you need to know the type of the pointer what is.

We know that the increase or decrease of 1 in the operation of the pointer means that the size of the type represented by the pointer needs to be offset by the number of bytes. is 4 bytes), so this is also a need to know the type of the pointer.

pointers and arrays

Literally speaking, pointers and arrays are inaccessible. They are supposed to be well water and not river water. How can they be involved? We often hear about array pointers and pointer arrays. What do these mean? Are they pointers or arrays? The following will answer you one by one.

An array of pointers, first of all, it is an array, and each element in the array is a pointer. For example, it is an array of int *p[4]pointers, because the operator []has a *high priority, so the ppriority sum []is formed into an array, and then it is combined *with the type int The type to combine into the elements of the array.
For example, the following program is an example of an array of pointers:

main.c
#include <stdio.h>
int main(){
    char *str[3] = {
        "我是数组1",
        "我是数组2",
        "我是数组3"
    };
    printf("%s\n%s\n%s\n", str[0], str[1], str[2]);
    return 0;
}

Array pointer, first of all, it is a pointer. The object pointed to by this pointer is an array. For example, if this pointer is p, then the content obtained by dereferencing *pis an array. For example int (*p)[4], the idea is to put parentheses.
Usually, the array pointer is also used as a two-dimensional array. use.

secondary pointer

The so-called second-level pointer is actually a pointer to a pointer, such int **pas a second-level pointer. The object stored in it is a pointer. The address of the pointer stored in the memory is obtained through a dereference. Dereferencing can be used to get
the value of this real content.

It's a bit confusing to understand, so what is the role of this mouth-watering secondary pointer? The second-level pointer may not be used much in C++, but it is a weapon that is often used in C. It is usually used as a parameter of a function to initialize a pointer inside the function,
such as classic audio and video. FFmpegSecondary pointers are used extensively in processing tools .
The following example shows how to assign a value to a pointer form through a secondary pointer:

main.cpp
void initP(int **p){
    *p = new int(10);
}

int main() {
    int *p = nullptr; // 一个空的指针
    initP(&p); // 通过二级指针初始化指针p
    std::cout << "*p的值:" << *p << endl;
    delete p;
    return 0;
}

Maybe someone here is as confused as when the author first came into contact with the C language. Can't we initialize the pointer by passing a first-level pointer to the function? This is not possible. This is because of the value transfer. For example, children's shoes who have discussed in depth can write an example and print the specific address of the actual parameter to compare and study the principle behind it.

Pointers and Polymorphic Binding

We all know that C++ is an object-oriented design language, and support for polymorphism is one of its important features. When learning about C++ classes, the teacher told us: *In C++ language, when we use base classes Dynamic binding occurs when a reference (or pointer) of a virtual function is called. * That is to
say, using a pointer or reference through the parent class can call different virtual functions according to whether the actual type of the actual parameter is the parent class or the child class.

For example the following code:

main.cpp
class Base{
public:
    virtual void print() const{
        std::cout << "base print" << endl;
    }

    virtual ~Base(){

    }
};

class Child:public Base{
public:
    void print() const override{
        std::cout << "Child print" << endl;
    }
};

void testPrint(const Base &base){
    base.print();
}

int main() {
    Base a = Child();
    testPrint(a);// 打印Base print
    Child b = Child(); // 注意,不能写成Base b = Child(),否则打印的是Base的print
    testPrint(b); // 打印Child print
    Base *c = new Child(); // 指针,动态类型与静态类型不一致
    testPrint(*c); // 打印Child print

    Base &&r = Child(); // 表达式是右值引用,动态类型与静态类型不一致
    testPrint(r); // 打印Child print
    return 0;
}

Why in the above program athe actual type of the variable is Child, but testPrintthe print method of the parent class is called inside the function? Doesn't it mean that references trigger polymorphism? Functions testPrintare also passed by reference, which is
really incredible.

To solve this doubt, you have to understand the knowledge of static typing and dynamic typing. The static type is always known at compile time. First, the static type is the type of the variable declaration or the type generated by the expression; the dynamic type is the type of the object in memory represented by the variable or expression, and the dynamic type is not known until runtime. know.
If the variable expression is neither a reference nor a pointer at the time of definition, its dynamic type will always be the same as the static type, that is, the type indicated at the time of declaration, otherwise the static type may be inconsistent with the dynamic type.

So after having the concepts of static type and dynamic type and then looking at the above sample code with comments, is there a feeling of seeing the sky above the clouds?

function pointer

A function pointer, as its name implies, is a pointer to a function, and its definition: a function pointer is a pointer variable that points to a function. Therefore, the "function pointer" itself should first be a pointer variable, but the pointer variable points to a function.

The way it is declared is:

返回值类型 (*函数名) (参数)  

An important use of the function pointer is as a parameter of the function, which is used to call the pointer function inside the function. It is generally used as a callback function. For example, when a POSIX thread is created, a function pointer needs to be passed to indicate what the thread should do. matter.

The following code shows the use of a simple function pointer:

void testFunc(int a,int b,void (*func)(int c,int d) ){
    // do something
    func(a,b);
}

void callback(int a,int b){
    
}

int main() {
    testFunc(1,2,callback);
    return 0;
}

class member pointer

Here, the class member pointer represents a pointer to a non-static member of an object of the class, not a pointer to a class member variable. First of all, it is necessary to distinguish these two different concepts. If the two concepts cannot be distinguished well Children's shoes, need to think again.

The type of the member pointer includes the type of the class and the type of the member. When initializing such a pointer, we make it point to a member of the class, but do not specify the object to which the member belongs; the object to which the member belongs is not provided until the member pointer is used.

Like other pointers, when declaring member pointers we also use * to indicate that the currently declared name is a pointer. Unlike ordinary pointers, member pointers must also contain the class to which the member belongs. Here is an example of usage:

class Person{
public:
    virtual void print() const{
        std::cout << "base print" << endl;
    }

    virtual ~Person(){

    }

public:
    string lastName;
    string firstName;
};

int main() {
    string Person::*p; // 声明了一个类成员指针
    p = &Person::firstName; // 成员变量的指针指向了Peron的name
    Person person;
    person.*p = "hello"; // 使用成员指针
    p = &Person::lastName; // 成员变量的指针指向了Peron的lastName
    person.*p = "world"; // 使用成员指针
    std::cout << person.firstName << " " << person.lastName << std::endl;
    return 0;
}

As for what is the use of this member pointer, I feel that I have given an alias again, and I even take off my pants and fart? But existence is reasonable, it's not useless, it's just that the author has seen that kind of scene. . .

In addition to pointers to class member variables, there are also pointers to class member functions, so I won't discuss more here! ! !

Follow me, make progress together, life is more than coding! ! !
WeChat scan code to follow

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324098969&siteId=291194637