Embedded Software Engineer written interview guide – C / C++

Time:2021-5-11

Hello, everyone. In recent days, I have rearranged and classified some of the contents of the written interview summarized in last autumn’s recruitment. It’s divided into three partsResume writing, interview skills, face to face summary, written interview eight part essay summaryAnd so on four parts.

Among them, the eight part essay is divided into three partsC/C++Data structure and algorithm analysisArm system and architectureLinux driver developmentoperating systemNetwork programmingReal questions of famous enterprises’ written examinationAnd so on seven parts. In this eight part essay update, some inappropriate contents have been deleted and C + + related contents have been added.

The content of the above seven parts will be updated synchronously in GitHub, link https://github.com/ZhongYi-Li… .I hope you can give a star supportLet me have the motivation to continue to update. When all the content is updated, it will be integrated into PDF. If you don’t say much, take a look at the table of contents.

Warning: This article is very long, very long, very long! If you don’t have the patience to read all the suggestions, you can jump to GitHub directly to get the PDF download method

Embedded Software Engineer written interview guide - C / C++

C/C++

keyword

The usage of “#” and “#” in C language macro

  1. (#) stringization operator

Function: convert the incoming parameter name in the macro definition into a parameter name string enclosed in a pair of double quotation marks. It can only be used in a macro definition with an incoming parameter and must precede the parameter name in the body of the macro definition.

For example:

#define example( instr )  printf( "the input string is:\t%s\n", #instr )
#Define example1 (instr) # instr when using this macro definition:
example( abc ); //  At compile time, the input string will be opened as: printf ("the input string is: T% s, n", "ABC")
string str = example1( abc );  //  It will be: String STR = "ABC"
  1. (#) symbolic join operator

Function: convert multiple formal parameters defined by macro into an actual parameter name.

For example:

#define exampleNum( n )  num##n

use:

int num9 = 9;
int num = exampleNum( 9 ); //  Will be expanded to int num = Num9

be careful

a. When using # #, the spaces before and after #, are optional.

For example:

#define exampleNum( n )       num ## n                 
//It is equivalent to # define examplenum (n) num # n

b. The actual parameter name after connection must be an actual parameter name or a macro definition known by the compiler.

c. If the parameter after #, itself, is also a macro, #, will prevent the expansion of the macro.

#include <stdio.h>
#include <string.h>

#define STRCPY(a, b)   strcpy(a ## _p, #b)
int main()
{
    char var1_p[20];
    char var2_p[30];
    strcpy(var1_p, "aaaa");
    strcpy(var2_p, "bbbb");
    STRCPY(var1, var2);
    STRCPY(var2, var1);
    printf("var1 = %s\n", var1_p);
    printf("var2 = %s\n", var2_p);

    //STRCPY(STRCPY(var1,var2),var2);
    //Will it expand to: strcpy (strcpy (VAR1)_ p,"var2")_ p,"var2“)? The answer is no:
    //The expansion result will be: strcpy (strcpy (VAR1, var2)_ p,"var2")
    //##Macro expansion of parameters is blocked! If # and # are not used in the macro definition, the macro will be fully expanded
    //If you open the comment, an error will be reported: implicit declaration of function 'strcpy'
    return 0;
}

result:

var1 = var2
var2 = var1

What is the meaning of the keyword volatile? And three different examples?

  1. Hardware registers of parallel devices. Memory mapped hardware registers are usually volatile, because registers can be modified by peripheral hardware at any time. When declaring a pointer to a device register, be sure to use volatile, which tells the compiler not to make assumptions about the data stored at this address.
  2. A variable modified in an interrupt service program for detection by other programs. Volatile reminds the compiler that the variables defined after it can change at any time. So every time the compiled program needs to store or read this variable,Will read data directly from the variable address. If there is no volatile keyword, the compiler may optimize reading and storage, and may temporarily use the value in the register. If this variable is updated by another program, there will be inconsistency.
  3. Variables shared by several tasks in multithreaded applications. In other words, it prevents the compiler from optimizing the code
XBYTE[2]=0x55;
XBYTE[2]=0x56;
XBYTE[2]=0x57;
XBYTE[2]=0x58;

For external hardware, the above four statements represent different operations and will produce four different actions, but the compiler will optimize the above four statements,Only xbyte [2] = 0x58 is consideredThat is, the first three statements are ignored and only one machine code is generated)。 If you type volatile, the compiler will compile one by one and generate the corresponding machine code (four codes).

What is the function of the keyword static?

  1. In the function body,It will only be initialized onceA variable that is declared static maintains its value during the call of the function.
  2. Within the module (but within theFunction in vitro), one declared asStatic variablesIt can be accessed by the functions used in the module, but not by other functions outside the module. It’s aLocal global variables(can only be used by the current file).
  3. Within a module, aStatic functionThe first mock exam can only be invoked by other functions in this module. That is, the function is restricted to the local scope of the module that declares it(Can only be used by the current file)。

In C language, why is static variable initialized only once?

For all objects (not just static objects),Initialization is only onceBecause of the memory function of static variables, they are not destroyed after initialization,Will be saved in the memory area, so it is not initialized again. The life cycle of the variable stored in the static area is generally long. It is the same as the whole program, so it only needs to be initialized once. And auto variable, that is, automatic variable, because itStored in stack areaAs soon as the function call ends, theDestroyed immediately

What is the function of “external” C “?

The main function of extern “C” is to correctly implement C + + code to call other C language code. After adding extern “C”, theIndicates that the compiler compiles this part of the code according to the C language, not c + +.

What does const do?

  1. Define a variable (local or global) as a constant, for example:
const int N=100;// Define a constant n
N=50; // Error, constant value cannot be modified
const int n; // Error, constant must be initialized when defined
  1. Modify the parameter of a function to indicate that the value of this parameter cannot be modified in the function body.
  2. Modifies the return value of a function.

    a. If you modify it with constThe return value is of type pointerThen the content of the function return value (that is, the pointer) is not validCan be modifiedAnd this return value can only be assigned to the pointer modified by const. For example:

    Const char getstring() // define a function
    Char * STR = getstring() // error, because STR is not modified by const
    Const char * STR = getstring() // correct

b. If you modify it with constNormal return valueFor example, if you return an int variable, because the return value is a temporary variable, the life cycle of the temporary variable will end after the end of the function call, so you can put these variablesThe return value decorated with const is meaninglessYes.

  1. Save space and avoid unnecessary memory allocation. For example:

    #Define PI 3.14159 // this macro is used to define constants
    Const doulbe pi = 3.14159 // P is not put into the ROM at this time
    Double I = pi // allocate memory for PI at this time, and do not allocate memory later
    Double I = pi // macro replacement and memory allocation during compilation
    Double J = pi // no memory allocation. Replace the macro again and allocate memory again

When to use the const keyword?

  1. Modify general constants. A general constant is a constant of a simple type. When defining this constant, the modifier const can be used before or after the type specifier. For example:
int const x=2;const int x=2
  1. Modification constant group. Define or describe a constant array in the following format:
int const a[8]={1,2,3,4,5,6,7,8}
const int a[8]={1,2,3,4,5,6,7,8}
  1. Modify the object. Constant objects refer to object constants. The definition format is as follows:
class A:
const A a:
A const a:

When defining a constant object, it is also initialized, and the object can no longer be updated. The modifier const can be placed after or before the class name.

  1. Modify constant pointer
const int*p; // For a pointer to a constant, the value of P can be changed, and the numerical content of P cannot be changed
int const*p; // The memory pointed by constant pointer P cannot be changed, but the value pointed by P can be changed
int*const p;// Same as 2
const int* const p;// A constant pointer to a constant. That is, the memory and value of P are immutable
  1. Modifiers are often quoted. The reference variable modified by const is a constant reference. Once it is initialized, it can no longer point to other objects.
  2. Modify the constant parameter of a function. The const modifier can also modify the transfer parameter of a function in the following format:
void Fun(const int Var)

It tells the compiler that VaR can’t be changed in the function body, thus preventing the user from some unintentional or wrong modification.

  1. Modifies the return value of a function. The const modifier can also modify the return value of a function, indicating that the return value cannot be changed. The format is as follows:
const int FunI(); 
const MyClass Fun2();
  1. Reference the const constant in another connection file. How to use it
extern const int 1:
extern const int j=10;

What is the difference between new / delete and malloc / free?

  1. New and delete are operators in C + +, while malloc and free are standard library functions.
  2. For Non internal data objects, only using malloc can not meet the requirements of dynamic objects. Generally, when creating objects, we need to call the constructor. When objects die, we call the destructor automatically. Malloc free is a library function rather than an operator, which is beyond the control of the compiler and cannot call constructors and destructors automatically. New can automatically call the constructor and initialize the object when it applies for allocating memory space for the object. Similarly, delete can call the destructor automatically. Malloc just does one thing and allocates memory for variables. Similarly, free just releases memory for variables.
  3. New returns a pointer of the specified type, and can automatically calculate the size of the requested memory. Malloc requires us to calculate the size of the application memory and forcibly convert it to a pointer of the actual type on return.

strlen(“\0”) =? sizeof(“\0”)=?

strlen(“\0”) =0,sizeof(“\0”)=2。

Strlen is used to calculate the length of a string (in C / C + +, a string isEnding with ‘\ 0’)It starts to scan from a location in memory (which can be the beginning of a string, a location in the middle, or even an uncertain memory area) until it encounters the first string terminator, and then returns the counter value sizeof, which is the keyword of C languageByte formThe calculation of its operands is givenStorage sizeThe operands can be an expression or a type name enclosed in brackets. The storage size of operands depends on the type of operands.

What’s the difference between sizeof and strlen?

There are five differences between strlen and sizeof.

  1. Sizeof is an operator? In fact, sizeof is both a keyword and an operator (but not a function), while strlen is a function. After sizeof, if it is a type, it must be enclosed with brackets. If it is a variable name, it can be enclosed without brackets.
  2. The result type of the sizeof operator is size_ t. In the header file, typedef is of type unsigned int. This type is guaranteed to hold the byte size of the largest object established by the implementation
  3. Sizeof can take type as parameter, strlen can only take char * as parameter, and it must end with “0”. Sizeof can also take a function as a parameter. For example, int g (), then the value of sizeof (g ()) is equal to the value of sizeof (int). In 32-bit computers, the value is 4.
  4. The sizeof of most compilers is in thecompileSo we can define the dimension of the array by sizeof (x). And strlen is in theOperation periodCalculated, used to calculate the actual length of the string, not the memory size of the type. For example, char STR [20] = “0123456789”, character array STR isCompilation periodThe size of the fixed array is sizeof (char) * 20 = 20 on 32-bit machine, while the strlen size isOperation periodSo the value is the actual length of the string 10.
  5. When an array is passed to a function as a parameter, the pointer is passed instead of the array, that is, the first address of the array is passed.

How to calculate the number of bytes occupied by int without sizeof?

#include <stdio.h>
#define MySizeof(Value)  (char *)(&value+1)-(char*)&value
int main()
{
    int i ;
    double f;
    double *q;
    printf("%d\r\n",MySizeof(i));
    printf("%d\r\n",MySizeof(f));
    printf("%d\r\n",MySizeof(a));
    printf("%d\r\n",MySizeof(q));
    return 0;
}

The output is:

4 8 32 4

   in the above example,(char*)& ValueReturns the first byte of the address of value,(char*)(& Value+1)Returns the first byte of the next address to the address of value, so the difference is the number of bytes it occupies.

What is the difference between struct and union in C language?

Struct (structure) and Union (Union) are two different data structures in C language. Both of them are common composite structures. Their differences are mainly shown in the following two aspects.

  1. Although structure and union are composed of many different data type members, the difference lies in all members of the unionShare one address spaceThat is to say, the union only stores one selected member, while the space occupied by all members in the structure is cumulative, all members exist, and different members will be stored in different addresses. When calculating the total length of a structural variable, the size of its memory space is equal to the sum of the lengths of all members (byte alignment needs to be considered). However, in a union, all members cannot occupy the memory space at the same time, and they cannot exist at the same time, soThe length of a union variable is equal to the length of its longest member
  2. For different members of the consortium,Will be rewritten for its other membersThe value of the original member does not exist, and the assignment to different members of the structure does not affect each other.

for instance. What is the result of the following code execution?

typedef union {double i; int k[5]; char c;}DATE;
typedef struct data( int cat; DATE cow;double dog;)too;
DATE max;
printf ("%d", sizeof(too)+sizeof(max));

Suppose it is a 32-bit machine, with 4 bytes for int, 8 bytes for double and 1 byte for char. Date is a union variable, which shares the same space. The largest variable type in Uion is int [5],So it takes 20 bytes, and its size is 20Because the double in the union takes up 8 bytes, the union should be aligned with 8 bytes,The memory space is a multiple of 8. To achieve 8-byte alignment,The space occupied is 24Data is a structure variable, and each variable takes up space separately. The order is sizeof (int) + sizeof (date) + sizeof (double) = 4 + 24 + 8 = 36. The space occupied is 40, so the result is 40 + 24 = 64.

What are left and right values?

Lvalue refers to the variable or expression that can appear on the left side of the equal signWritable(addressable). That is to say, its valueIt can be modified, if oneThe value of a variable or expression cannot be modifiedThen it can’t be left-handed.

The right value refers toVariables or expressions that can only appear to the right of the equal sign. Its most important feature isreadable. The general use scenario is to assign a right value to a left value.

Generally, the left value can be used as the right value, but the right value is not necessarily the left value.

What is short circuit evaluation?

#include <stdio.h>
int main()
{
   int i = 6;
   int j = 1;
   if(i>0||(j++)>0);
   printf("%D\r\n",j);
   return 0;
}

The output is 1.

Why is the output not 2, but 1? In fact, there is a problem of short circuit calculation. Because I statement is a conditional judgment statement, which is a compound statement with two simple statements for or operation combination, because in or operation, as long as the values of the two expressions participating in or operation are true, the whole operation result is true. Because the value of variable I is 6, which is greater than 0, and the statement is true, there is no need to perform subsequent j + operation to judge whether it is true or not, Therefore, the subsequent j + + operations do not need to be executed, and the value of J is still 1.

Because of the problem of short-circuit calculation, for the & & operation, if one of the return values of the two expressions is false, the value of the whole expression will be false. If the return value of the previous statement is false, whether the return value of the later statement is true or false, the whole condition judgment will be false, and the latter statement will not be executed, and the return value of a > b is false, The program does not execute the expression n = C > D, so the value of N remains the initial value of 2.

++What’s the difference between a and a +? How are the two realized?

The specific operation process of a + + is as follows

int temp = a;
a=a+1;
return temp;

++The specific operation process of a is as follows

a=a+1;
return a;

The post autoincrement operator needs to copy the value of the original variable to aTemporary storage spaceThe value of this temporary variable will not be returned until the end of the operation. Therefore, the efficiency of pre auto increment operator is higher than that of post auto increment operator

Memory

How many ways of memory allocation in C language?

  1. Static storage allocation

Memory allocation is completed before the program is compiled, and exists throughout the running of the program, such as global variables, static variables, etc.

  1. On stack allocation

When the function is executed, the storage units of local variables in the function are created on the stack, and these storage units are automatically released at the end of the function execution.

  1. Heap allocation

What’s the difference between heap and stack?

  1. Application method

    The stack space is automatically allocated / released by the operating system, and the heap space is manually allocated / released.

  2. Application size limit
    Stack space is limited. In windows, the stack is toLow addressThe extended data structure is a blockA contiguous area of memory. The address at the top of the stack and the maximum capacity of the stack are predetermined by the system. Under windows, the size of the stack is 2m (or 1m, in short, a constant determined at compile time). If the space applied exceeds the remaining space of the stack, overflow will be prompted. Therefore, it canThe space obtained from the stack is small

    A heap is a large free storage area. The pile is toHigh addressThe extended data structure is a discontinuous memory area. This is because the system is usedList to store the free memory address, which is naturally discontinuous, and the traversal direction of the linked list is from the low address to the high address. The size of the heapLimited by effective virtual memory in computer system. It can be seen that the space obtained by heap is relatively flexible and large.

  3. Application efficiency
    The stack is automatically allocated by the system, and the speed is fast. But programmers can’t control it.

    Heap is the memory allocated by new. Generally, it is slow and easy to generate memory fragments

What role does stack play in C language?

  1. Stack is used to store temporary variables in C languageFunction parameters and temporary variables defined inside the function. Related to a function callFunction return addressThe temporary variables and registers in the function are stored in the stack. After the function is transferred and returned, the function operation scenarios such as registers and temporary variables are recovered from the stack.
  2. The foundation of multithreading programming is stack,Stack is the cornerstone of multithreading programmingEach thread at least has its own stack, which is used to store the temporary variables of each function when the thread is running, and maintain the function call relationship and function running scenarios when the function calls and returns. The most basic function of operating system is to support multithreading programming, interrupt and exception handling. Each thread has its own stack, and interrupt and exception handling also has its own stack. Stack is the cornerstone of multithreading management of operating system.

C language function parameters stack order is how?

From right to left.

The advantage of C language parameter stack order is that it can dynamically change the number of parameters. In the stack mode from left to right, the front parameters are pressed at the bottom of the stack. Unless the number of parameters is known, the leftmost parameters cannot be obtained by the relative displacement of the stack pointer. In this way, the number of parameters on the left is uncertain, just opposite to the number of dynamic parameters. Therefore, the function parameters of C language are put into the stack from right to left, mainly to support variable length parameters.

How does C + + handle return value?

C + + function returns can be returned by value, by constant reference, and occasionally by index. In most cases, do not use index return.

Can the formal parameters of copy assignment function be transferred in C + +?

No. If this is the case, when calling the copy constructor, you should first pass the actual parameter to the formal parameter, and then call the copy constructor (AA = ex.aa// The copy constructor is called here). If this loop fails to complete the copy, the stack will be full.

class Example
{
public:
    Example (int a): AA (a) {} // constructor
 
    Example (example & Ex) // copy constructor (pass parameter by reference)
    {
        aa = ex.aa;                // The copy constructor is called here
    }
private:
    int aa;
};
 
int main()
{
    Example e1(10);
    Example e2 = e1;
    
    return 0;
}

What is the memory management of C + +?

In C + +, virtual memory is divided into two partsCode segment, data segment, BSS segment, heap area, file mapping area and stack areaSix parts.

Code snippet: including read-only memory area and text area, in which read-only memory area stores string constants and text area stores machine code of program.

Data segment: stores initialized global and static variables in a program

BSS section: stores uninitialized global variables and static variables (local + global), as well as all global variables and static variables initialized to 0.

Heap area: when the new / malloc function is called, the memory is allocated dynamically in the heap. At the same time, delete / free is called to release the requested memory manually.

map section: store dynamic link library and file mapping by calling MMAP function

Stack: use stack space to store the return address, parameter, local variable and return value of the function

What is a memory leak?

In short, it is to apply for a piece of memory space, which is not released after use.

Its general way of expression is that the longer the program runs, the more memory it occupies, and eventually the whole system crashes. A piece of memory requested by the program, and no pointer points to it, then this piece of memory is leaked.

How to judge a memory leak?

  1. Good coding habits, try to detect memory leaks in the program segments involving memory. When the program is stable, it will increase the difficulty and complexity to detect memory leak. Once the memory allocation function is used, remember to use its corresponding function to release it.
  2. The pointer of the allocated memory is managed by itself in the form of linked list. After use, it is deleted from the linked list. At the end of the program, the linked list can be checked and changed.
  3. Smart pointer in boost.
  4. Some common tool plug-ins, such as ccmalloc, dmalloc, leaky, etc.

Pointer

What’s the difference between an array pointer and an array of pointers?

An array pointer is a pointer to an array. What it represents is a pointer. This pointer points to an array. Its key point is the pointer. For example,int(*pa)[8]Declares a pointer to an array of 8 int elements. Here is an example of an array pointer.

#include <stdio. h>
#include <stdlib. h>
void main()
{
    int b[12]={1,2,3,4,5,6,7,8,9,10,11,12};
    int (*p)[4];
    p = b;
    printf("%d\n", **(++p);
}

The output of the program is 5.

In the example above, P is an array pointer to an arrayContains four int typesIn the beginning, P is initialized to the first address of array B, and + + P is equivalent to the address P points toSpace occupied by moving 4 ints backwardIn this case, P points to the array {5,6,7,8}, and the statement*(++p);Represents the number of objects in this arrayThe first elementP is a pointer to a two-dimensional array, {1,2,3,4}, {5,6,7,8}, {9,10,11,12}. P refers to the address of {1,2,3,4},*pIt’s pointing to the element, {1,2,3,4},**pThe statement * * (+ P) will output the first element 5 of the array.

A pointer array represents an array, and the elements in the array are pointers. Here’s another example of a pointer array

#include <stdio.h>
 int main()
 {
    int i;
    int *p[4];
    int a[4]={1,2,3,4};
    p[0] = &a[0];
    p[1] = &a[1];
    p[2] = &a[2];
    p[3] = &a[3];
    for(i=0;i<4;i++)
        printf("%d",*p[i]);
    printf("\n"); 
    return 0;
}

The output of the program is 1234.

What’s the difference between a function pointer and a pointer function?

  1. Function pointer

If a function is defined in the program, the system will allocate a storage space for the function code at compile time. The first address of this storage space is called theThe address of the function. And the function name represents the address. Since it is an address, we can define a pointer variable to store it. This pointer variable is called function pointer variableFunction pointer

int(*p)(int, int);

This statement defines a pointer variable p to the function. First of all, it is a pointer variable, so there should be a “*”, that is(*p); Secondly, the previous int indicates that the pointer variable can point to the function whose return value type is int; The two ints in brackets indicate that the pointer variable can point to a function with two parameters and both are int type. So together, the meaning of this statement is: define a pointer variable p, which can point to a function with return value type of int and two integer parameters. The type of P isint(*)(int,int)

We can see that the definition of function pointer is to change “function name” in “function declaration” to “function name”“(Pointer variable name. But here we need to pay attention to:“(Pointer variable name)Brackets at both ends cannot be omittedThe parentheses change the priority of the operator. If you omit the brackets, you will not define a function pointer, but a function declaration, that is, you will declare a function whose return value type is pointer type.

Finally, it should be noted that pointer variables to functions do not have + + and — operations.

# include <stdio.h>
int Max(int, int);  // Function declaration
int main(void)
{
    int(*p)(int, int);  // Define a function pointer
    int a, b, c;
    p = Max;  // Assign the function max to the pointer variable p so that P points to the max function
    printf("please enter a and b:");
    scanf("%d%d", &a, &b);
    c = (*p)(a, b);  // Calling Max function through function pointer
    printf("a = %d\nb = %d\nmax = %d\n", a, b, c);
    return 0;
}
Int max (int x, int y) // define Max function
{
    int z;
    if (x > y)
    {
        z = x;
    }
    else
    {
        z = y;
    }
    return z;
}
  1. Pointer function

First of all, it is a function, but the return value of this function is an address value. Function return value must be accepted by pointer variable of the same type, that is to say, pointer function must have “function return value”. Moreover, in the main calling function, function return value must be assigned to pointer variable of the same type.

Type name * function name (function parameter list);

Among them, the suffix operator bracket “()” indicates that this is a function, and the prefix operator star “*” indicates that this function is a pointer type function, and its function value is a pointer, that is, the type of the value it brings back is a pointer. When this function is called, it will get a “pointer (address) with a return value of…”, Type name indicates the type to which the pointer returned by the function points.

The brackets in “function parameter list” are function call operators. In a call statement, even if a function has no parameters, a pair of brackets in its parameter list cannot be omitted. Examples are as follows:

int *pfun(int, int);

Since the priority of “*” is lower than that of “()”, pfun is first combined with “()”, which means that pfun is a function. Namely:

int *(pfun(int, int));

Then combined with the previous “*” to show that the return value of this function is a pointer. Because there is an int in the front, that is to say, pfun is a function whose return value is an integer pointer.

#include <stdio.h>
 float *find(float(*pionter)[4],int n);// Function declaration
 int main(void)
 {
     static float score[][4]={{60,70,80,90},{56,89,34,45},{34,23,56,45}};
     float *p;
     int i,m;
     printf("Enter the number to be found:");
     scanf("%d",&m);
     printf("the score of NO.%d are:\n",m);
     p=find(score,m-1);
     for(i=0;i<4;i++)
         printf("%5.2f\t",*(p+i));
  
     return 0;
 }
 
Float * find (float (* pionter) [4], int n) / * defines pointer functions*/
 {
     float *pt;
     pt=*(pionter+n);
     return(pt);
 }

There are three students’ grades. The function find() is defined as a pointer function, and its parameter pointer is a pointer to a one-dimensional array containing four elements. Pointer + n points to line n + 1 of the score*( Pointer + 1) points to the 0 th element in the first row. PT is a pointer variable that points to a floating-point variable. The find () function is called in the main () function to transmit the first address of the score array to pointer.

What is the difference and connection between array name and pointer?

  1. Data preservation

The pointer saves the address (the address of the target data is saved, and its own address is allocated by the compiler), and the memory access offset is 4 bytes. No matter what kind of data is saved, the address type has been resolved.

Array to save data. The array name represents the address of the first element, and the memory offset is the memory offset to save the data type; Only when the address (& array name) of the array name is taken, the array name represents the entire array,The memory offset is the size of the entire array (sizeof)

  1. Data access

The pointer’s access to data is indirect, and the dereference symbol (* array name) is needed.

Array access to data is direct access, which can be accessed by subscript or array name + element offset

  1. Use environment

Pointers are mostly used for dynamic data structures (such as linked lists, etc.) and dynamic memory development.

Arrays are mostly used to store fixed number and uniform data structures (such as linear table, etc.) and implicit allocation.

What is the result of the addition operation between pointer and address after castable?

Suppose that on a 32-bit machine, when the alignment is 4, the result of sizeof (long) is 4 bytes, the result of sizeof (char *) is 4 bytes, the result of sizeof (short int) and sizeof (short) are 2 bytes, the result of sizeof (char) is 1 byte, and the result of sizeof (int) is 4 bytes

struct BBB 

{

  long num;

  char *name;

  short int data;

  char ha;

  short ba[5];

}*p;

Whenp=0x100000;bep+0×200=? (ulong)p+0x200=? (char*)p+0x200=?

In fact, on 32-bit machines,Sizeof (struct BBB) = sizeof (* P) = 4 + 4 + 2 + 2 + 1 + 3 / * completion * / + 2 * 5 + 2 / * completion * / = 24 bytes, andp=0x100000Sop+0x200=0x1000000+0x200*24Pointer addition adds an integer multiple of the byte length of the type the pointer refers to, that is, P offset sizeof (P) * 0x200.

(ulong)p+0x200=0x10000010+0x200After ulong, it is no longer a pointer addition, but a numerical addition.

(char*)p+0x200=0x1000000+0×200*sizeof(char)The result type is char *.

What’s the difference between a constant pointer, a pointer to a constant, and a constant pointer to a constant?

  1. const pointer
int * const p

Let’s look at const first, and then * where p is a pointer to a constant type,You cannot change the direction of this pointerBut this pointer is stored at the addressThe value can be modified

  1. pointer to const
const int *p

First look at * and then look at const. Define a pointer to a constant. You can’t modify the pointer through the pointerThe value that points to

  1. Constant pointer to a constant
const int *const p

For “constant pointer to constant”, the contents of 1 and 2 above must be met at the same time,You can neither modify the value of the pointer nor the value the pointer points to

What are the similarities and differences between pointers and references? How to transform each other?

identical

  1. Both are the concept of address. The pointer points to a memory, and its content is the address of the memory; A reference is an alias for a block of memory.
  2. From the memory allocation point of view: both occupy memory, the program will allocate memory for the pointer, generally 4 bytes; The essence of a reference is a pointer constant, which can’t be changed but can be changed. Both are address concepts, so they both occupy memory.

difference

  1. A pointer is an entity and a reference is an alias.
  2. The meaning of pointer is different from that of reference (+ +) operator. Pointer is self incrementing to memory address, while reference is self incrementing to value.
  3. When using a reference, there is no need to dereference (*), and the pointer needs to dereference( About dereference, you can see this blog, portal).
  4. A reference can only be initialized once when it is defined, and then it is immutable; The pointer is variable.
  5. Reference cannot be null, pointer can be null.
  6. “Sizeof reference” gets the size of the variable (object) it points to, while “sizeof pointer” gets the size of the pointer itself. In 32-bit systems, pointer variables generally occupy 4 bytes of memory.
#include "stdio.h"

int main(){
    int x = 5;
    int *p = &x;
    int &q = x;
    
    printf("%d %d\n",*p,sizeof(p)); 
    printf("%d %d\n",q,sizeof(q));
} 
//Results
5  8
5  4

The results show that there is no need to dereference (*) when using the reference, but the pointer needs to dereference; I use a 64 bit operating system, and what I get from “sizeof pointer” is the size of the pointer itself and 8 bytes. The “sizeof reference” gets the size of the object itself and the size of int, 4 bytes.

transformation

  1. Pointer to reference: the pointer can be converted to an object with * and can be used in reference parameters.
  2. Reference pointer: Use & to get the address of the object of reference type to get the pointer.
int a = 5;
int *p = &a;
Void fun (int & x) {} // if you call fun, you can use: fun (* P);
//P is a pointer. After adding a * sign, it can be converted to the object that the pointer points to. At this time, the formal parameter of fun is a reference value,
//The object pointed to by the P pointer is converted to a reference X.

What is a wild pointer?

  1. A wild pointer is a pointer to unavailable memory. When a pointer is created, the pointer cannot automatically point to null. At this time, the default value is random, and the pointer becomes a wild pointer.
  2. When the pointer is released by free or delete, if the pointer is not set to null, a wild pointer will be generated, because only the memory pointed to by the pointer is released, and the pointer itself is not released.
  3. The third reason for wild pointers is that pointer operations go beyond the scope of variables.

How to avoid wild pointer?

  1. Initializes the pointer.
//Initializes the pointer to null.
char *   p  = NULL;
//Using malloc to allocate memory
char * p = (char * )malloc(sizeof(char));
//Initialize the pointer with a valid memory address
char num[ 30] = {0};
char *p = num;
  1. After the pointer is used up, free the memory and assign null to the pointer.
delete(p);
p = NULL;

Note: after malloc function allocates memory, it should be noted that:

a. Check whether the allocation is successful (if the allocation is successful, return the first address of the memory; Allocation unsuccessful, return null. It can be judged by the if statement.)

b. Clear the data in the memory (there may be garbage value in the space allocated by malloc, use memset or bZero function to clear the memory)

//S is the starting address of the space to be zeroed; N is the number of data bytes to be zeroed.
void bzero(void *s, int n);
//If the first address of the space to be cleared is p, value is the value, and size is the number of bytes.
void memset(void *start, int value, int size);

What is the smart pointer in C + +?

A smart pointer is a class that stores pointers (pointers to dynamically allocated objects).

Heap memory is a very frequent operation in C + + programming. The application and release of heap memory are managed by the programmer himself. The programmer can improve the efficiency of the program by managing the heap memory, but on the whole, the management of heap memory is troublesome. The concept of intelligent pointer is introduced into C + + 11 to facilitate the management of heap memory. Using ordinary pointer is easy to cause heap memory leakage (forget to release), secondary release, memory leakage when the program is abnormal, and so on. Using intelligent pointer can better manage heap memory.

How to solve the memory leak of smart pointer?

In order to solve the memory leakage caused by circular reference, weak pointer is introducedweak_ptrweak_ptrIt is similar to a common pointer, but it does not point to the shared memory of the reference count. However, it can detect whether the managed object has been released, so as to avoid illegal access.

Pretreatment

What is the purpose of the preprocessor identifying error?

\#The function of the error preprocessing instruction is to generate an error whenever # error is encountered when compiling a programCompile error messageAnd stop compiling. Its syntax format is: # error error message.

Here’s an example:
There are many preprocessing instructions in the program

#ifdef XXX
...
#else
#endif

When the program is relatively large, some macro definitions are usually specified externally (such as makefile) or in the system header file. When you are not sure whether XXX is currently defined, you can compile as follows:

#ifdef XXX
...
#error "XXX has been defined"
#else
#endif

In this way, if an error occurs during compilation, the output of XXX has been defined indicates that the macro XXX has been defined.

Who is better to define constants# Define or const?

Both define and const can define constants. Although the effect is the same, they have different emphases.

Define can replace not only constant values, but also expressions and even code segments, but it is easy to make mistakes. The introduction of const can enhance the readability of the program, which makes the maintenance and debugging of the program more convenient. Specifically, their differences are mainly manifested in the following three aspects.

  1. Define is just forSimple text replacement, define constantThe life cycle ends at compile timeDo not allocate memory spaceIt exists in theCode snippetIn practical program, it is just a constant; The const constant exists in theData segment, and inSpace is allocated in the stackConst constant exists in the program, and can be called and passed
  2. Const constants have data types, while define constants have no data types. The compiler can check the type security of const constants, such as type and statement structure, but define can’t.
  3. Many idesSupport debuggingConst defines the constant, but does not support the constant defined by define. Because const modifies the variable can eliminate the unsafe factors between programs, protect the constant in the program from being modified, and check the data type accordingly, which greatly improves the efficiency of the programRobustnessSo it’s normalWe prefer const to define constant types

What’s the difference between typedef and define?

Typedef and define are bothTake an alias for an objectIn order to enhance the readability of the program, but they also have the following four differences in use and function.

  1. The principle is different

    #Define is a syntax defined in C language. It is a preprocessing instruction, which makes a simple and mechanical string replacement during preprocessing,No correctness checkNo matter whether the meaning is correct or not, the possible errors will be found and reported only when compiling the expanded source program.

    For example,# define Pl3.1415926When the program is executedarea=Pr*rStatement, the PI is replaced with 3. 1415926. The statement is then replaced witharea=3.1415926*r*r. If the number 9 in the # define statement is written as G, the preprocessing will also be substituted, without checking whether it is reasonable and legal.

    Typedef is a keyword, which is processed at compile time, so typedef has the function of type checking. It gives an alias to an existing type in its own scope, but cannot use the identifier typedef in a function definition. For example,typedef int INTEGERAfter that, you can use integer instead of int as the type description of integer variables. For example:INTEGER a,b;

Using typedef to define array, pointer, structure and other types will bring great convenience, which not only makes the program writing simple, but also makes the meaning more clear, thus enhancing the readability. For example:typedef int a[10];

Indicates that a is an integer array type with an array length of 10. Then we can use a to describe variables, for example: statements a, S1, S2; Similarly, typedef void (* P) (void) indicates that P is a pointer type to void type.

  1. Different functions

    Typedef is used to define the aliases of types. These types include not only internal types (int, char, etc.), but also custom types (such as struct), which can make the types easy to remember.

For example:typedef int (*PF)(const char *, const char*)

Define the data type PF of a pointer to a function, where the return value of the function is int and the parameter is const char *. Another important use of typedef is to define machine independent types. For example, you can define a floating-point type called real, which can achieve the highest precision on the target machine:typedef long double REALOn a machine that does not support long double, the typedef looks like this:typedef double realOn a machine that doesn’t support double, the typedef looks like this:typedef float REAL

Define can not only take alias for type, but also define constant, variable, compile switch and so on.

  1. Different scopes

Define has no scope limit. As long as it is a pre-defined macro, it can be used in later programs, while typedef has its own scope.

The program example is as follows:

void fun()
{
    #define A int
}
void gun()
{
     //A can also be used here, because macro substitution has no scope, but if typedef is used above, it cannot be used here
     //A. However, typedef is not generally used within functions
}
  1. The operation of the pointer is different

They have different functions when modifying pointer types.

#define INTPTR1 int*
typedef int* INTPTR2;
INTPTR1  pl, p2;
INTPTR2 p3, p4;

The effects of intptr1, PL, P2 and intptr2, P3, P4 were different. Intptr1, PL, P2 becomeint*p1,p2The meaning of intptr2 is to declare a pointer variable P1 and an integer variable P2. Intptr2, P3, P4, because intptr2 has meaning, tells us that it is a pointer to integer data, so P3 and P4 are pointer variablesint*pl,*p2From this, we can see that macro replacement is a replacement without any meaning, just a string replacement; However, using typedef as an alias for a data type has a certain meaning.

An example of the procedure is as follows

#define INTPTR1  int*
typedef int* INTPTR2  
int a=1;
int b=2;
int c=3;
const INTPTR1  p1=&a; 
const INTPTR2 p2=&b;
 INTPTR2 const p3=&c;

In the above code, const intptr1 P1 means that P1 is a constant pointer, that is, the content pointed to by P1 cannot be modified through P1, but P1 can point to other content. For const intptr2 P2, because intptr2 represents a pointer type, it is restricted by const to indicate that the pointer type is blocked. Therefore, P2 is a pointer constant, and P2 can not point to other contents, but its current contents can be modified through P2. Intptr2 const P3 also declares a pointer constant.

How to use define to declare a constant to indicate how many seconds there are in a year (ignoring leap years)

#define SECOND_PER_YEAR (60*60*24*365)UL

What is the difference between include < file name. H > and include “file name. H”?

For include < file name. H >, the compiler first searches for file name. H from the standard library path to make the system file call faster. For # include “file name. H”, the compiler first searches the user’s working path for file name. H, and then searches the system path to make the custom file faster.

What are the functions of header files?

The function of header file mainly includes the following two aspects

  1. The library function is called through the header file. For the sake of keeping the source code secret, the source code is inconvenient (or not allowed) to be published to the user, as long as the header file and binary library are provided to the user. Users only need to call library functions according to the interface declaration in the header file, and do not care how the interface is implemented. The compiler extracts the corresponding code from the library.
  2. The header file can enhance the type security check. When an interface is implemented or used, if its way is inconsistent with the declaration in the header file, the compiler will point out the error, which greatly reduces the burden of debugging and correcting the error.

Is it possible to define static variables in the header file and why?

If static variables are defined in the header file, it will cause the problem of waste of resources, and it may also cause program errors. Because if you define static variables in each C language file that uses the header file, follow the compilation steps,There is a static variable in each header fileWhich can causeWaste of spaceperhapsProgram errorTherefore, it is not recommended to define any variables in the header file, including static variables.

Write a “standard” macro min, which inputs two parameters and returns the smaller one?

#define MIN(A,B) ((A) <= (B) ? (A) : (B))

How to print integers from 1 to 1000 without using process control statements?

Macro definition multi level nesting (10) 10 10) , printf output multiple times.

#include <stdio. h>
#define B P,P,P,P,P,P,P,P,P,P
#define P L,L,L,L,L,L,L,L,L,L
#define L I,I,I,I,I,I,I,I,I,I,N
#define I printf("%3d",i++)
#define N printf("n")
int main()
{
    int i = 1;
    B;
    return 0;
}

Easy to write, the same use of multi-layer nesting

#include<stdio. h>
#define A(x)x;x;x;x;x;x;x;x;x;
int main ()
{
    int n=1;
    A(A(A(printf("%d", n++);
    return 0;
}

variable

What is the difference between global variables and static variables?

  1. The scope of global variable is program block, while the scope of local variable is current function.
  2. Memory storage is different, global variables (static global variables, static local variables) are allocated in the global data area (static storage space), the latter is allocated in the stack area.
  3. The life cycle is different. Global variables are created with the creation of the main program and destroyed with the destruction of the main program. Local variables exist in local functions, even in local loop bodies, and exit does not exist.
  4. They are used in different ways. By declaring as global variables, all parts of the program can be used, while local variables can only be used locally.

Can global variables be defined in header files that can be contained by multiple. C files? Why?

Yes, it can be declared in static form in different C filesGlobal variable with the same name

Global variables with the same name can be declared in different C files, provided thatOnly one C file can assign an initial value to this variable, the connection will not go wrong.

Can local variables have the same name as global variables?

Yes, the local will shield the global.

A local variable can have the same name as a global variable. When the variable is referenced in a function, the local variable with the same name will be used instead of the global variable.

For some compilers, multiple local variables with the same name can be defined in the same function. For example, a local variable with the same name can be defined in both loops, and the scope of that local variable is in that loop.

function

Please write a function to run before executing the main function

__ attribute__ You can set function attribute, variable attribute, and type attribute.

GNU mainly sets the following keywords for function attributes:

Alias: set function alias.
        Aligned: sets the function alignment.
        always_inline/gnu_inline: 
                    Whether the function is inline.
        constructor/destructor:
                    Functions executed before and after the execution of the main function.
        format:
                    Specifies the position of the format input string of the variable parameter function and the corresponding format output.
        noreturn:
                    Specifies that this function has no return value.
                    Please note that there is no return value, not void. It's like_ Exit / exit / abord
                    A function in which the process ends after the function is executed.
        Weak: Specifies that the function attribute is a weak attribute instead of a global attribute. Once the global function name and the specified function name
             Name conflict, use global function name.

The complete sample code is as follows:

#include <stdio.h>

void before() __attribute__((constructor));
void after() __attribute__((destructor));

void before() {
    printf("this is function %s\n",__func__);
    return;
}

void after(){
    printf("this is function %s\n",__func__);
    return;
}

int main(){
    printf("this is function %s\n",__func__);
    return 0;
}

//Output results
// this is function before
// this is function main
// this is function after

Why must a destructor be a virtual function?

Setting the destructor of the parent class that may be inherited as a virtual function can ensure that when we create a new subclass, and then use the base class pointer to point to the subclass object, we can release the space of the subclass and prevent memory leakage when releasing the base class pointer.

Why is the default destructor of C + + not a virtual function?

The default destructor of C + + is not a virtual function, because the virtual function needs extra virtual function table and virtual table pointer, which takes up extra memory. For a class that will not be inherited, if its destructor is a virtual function, it will waste memory. Therefore, the default destructor of C + + is not a virtual function, but a virtual function only when it needs to be used as a parent class.

The function of destructor in C + +?

If the constructor opens a file, the file will be closed when it is not needed in the end. Destructors allow classes to do similar cleanup automatically without calling other member functions.

Destructors are also special class member functions. In short, the function of destructor and constructor is just the opposite, it is used to complete some cleaning work before the object is deleted, that is, special finishing work.

What is the difference between static function and virtual function?

Static functions have been determined when they are compiled, while virtual functions are dynamically bound when they are running. Because virtual function uses virtual function table mechanism, it will increase memory cost once when calling.

What’s the difference between overloading and overriding?

  1. Covering is the relationship between the subclass and the parent; Overloading the relationship between methods of the same class is a horizontal relationship.
  2. Coverage can only be related by one method or a pair of methods; Overloading is the relationship between multiple methods.
  3. The overlay is determined by the object type (the corresponding storage space type of the object); The overload relation selects the method body according to the actual parameter table and formal parameter table.

How to implement runtime polymorphism in virtual function table?

principle

The virtual function table is the address table of the virtual function of a class. When each object is created, there will be a pointer to the virtual function table of the class. According to the order of function declaration, the virtual function table of each class will store the function address in the virtual function table. When the subclass object rewrites the virtual function of the parent class, The corresponding position in the virtual function table of the parent class will be covered by the virtual function address of the subclass.

effect

When a member function of a subclass object is called with a pointer to the parent class, the virtual function table indicates which specific function to call.

How does C language call functions?

Program implementation on most CPUsUsing stack to support function call operationStack is used to transfer function parameters, store return information, temporarily save the original value of register for recovery and store local variables.

The part of the stack used by a function call operation is called theStack frame structureEach function call has its own stack frame structure. The stack frame structure is specified by two pointers, the frame pointer (pointing to the start) and the stack pointer (pointing to the top of the stack). Most data access of functions is based on the frame pointer. The following is the structure diagram:

Embedded Software Engineer written interview guide - C / C++

Stack pointer and frame pointer generally have special registers, usually using EBP register as frame pointer and ESP register as stack pointer.

The frame pointer points to the head of the stack frame structure, which stores the head address of the previous stack frame, and the stack pointer points to the top of the stack.

Please say select

  1. Prototype of select function
int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
  1. Number of file descriptors

There is a maximum limit on the number of file descriptors that a single process can monitor, usually 1024. Of course, the number can be changed( Define in Linux kernel header file: # define__ FD_ SETSIZE 1024)

  1. Ready FD scans by polling

Select returns int, which can be understood as one or more ready file descriptors. The application needs to traverse the entire file descriptor array to find out which FD handles have an event. Because select scans the file descriptors by polling (it does not know which file descriptor reads or writes data, so it needs to traverse all FD handles), The more the number of file descriptors, the worse the performance

  1. Kernel / user space memory copy

Every time select changes the handle data structure set (FD set) in the kernel, so every time select is called, all the handle data structures (FD sets) need to be copied from the user space to the kernel space, resulting in huge overhead

  1. Trigger mode of select

The trigger mode of select is horizontal trigger. If the application does not complete the IO operation on a ready file descriptor, it will still notify the process of these file descriptors every time it calls select.

  1. advantage

a. Select has good portability and can cross platform;

b. Select can set the monitoring time, the timeout precision is better, which can be accurate to microseconds, while poll is milliseconds.

  1. shortcoming

a. The maximum number of file descriptors supported by select is 1024, which cannot be changed according to user needs;

b. Every time select is called, the set of file descriptors is copied from user mode to kernel mode, which costs a lot;

c. The set of ready file descriptors returned by select requires the user to cycle through whether all the monitored file descriptors are in the set. When the number of listening descriptors is large, the timeliness rate is low.

Please talk about fork, wait and exec functions

When a parent process produces a child process, fork is used to copy a copy of the parent process. At this time, only the page table of the parent process is copied. Both processes read the same block of memory. When a process writes, the realistic copy mechanism is used to allocate memory. The exec function can load an ELF file to replace the parent process. From then on, the parent process and the child process can run different programs. Fork returns the PID of the child process from the parent process and 0 from the child process. The parent process that called wait will block until the state of the child process changes. 0 is returned for successful execution and – 1 is returned for error. If exec is successfully executed, the subprocess will start running from the new program, with no return value. If exec fails to execute, it will return – 1.

array

What does the following code mean?

*(a[1]+1)、*(&a[1][1])、(*(a+1))[1]

First: because a [1] is the address of line 2, a [1] + 1 offsets by one unit (get the address of line 2 and column 2), and then dereferences the value to get thea[1][1]

The second one is high priority, A1 takes the address and then takes the value.

Third: a + 1 is equivalent to & A [1], so(a + 1) = a [1], so(a+1)[1]=a1

Can array subscript be negative?

Yes, because the subscript just gives a relation with theThe offset of the current addressJust, as long as the target address can be located according to the offset. Here is an example of a negative subscript:

Negative value of array subscript:

#include <stdio.h>
int main()
{
    int i:
    int a[5]={0,1,2,3,4};
    int *p=&a[4]
    for(i=-4;i<=0;i++)
    printf("%d %x\n", p[i], &p[i]);
    return O.
}
//The output is
//0 b3ecf480
//1 b3ecf484
//2 b3ecf488
//3 b3ecf48c
//4 b3ecf490

It can be found from the above example that in C language, the subscript of an array can not be negative. When the subscript of an array is negative, the compilation can pass and the correct result can be obtained, but it means from the current addressForward addressing.

Bit operation

How to solve the number of 1 in binary representation of integer number?

The program code is as follows:

#include <stdio.h>
int func(int x)
{
    int countx = 0;
    while(x)
    {
        countx++;
        x = x&(x-1);
    }
    return countx;
}
int main()
{
    printf("%d\n",func(9999));
    return 0;
}

The output of the program is 8.

In the above example, the function func() converts x into a binary number, and then calculates the number of 1 contained in the binary number. First of all, take 9 as an example, the binary representation of 9 is 1001, and the binary representation of 8 is 1000. The result is 1000 after the two execute the & operation. At this time, 1000 and 0111 (the binary bit of 7) execute the & operation, and the result is 0.

In order to understand the core of this algorithm, we need to understand the following two operations:

1) When a number is subtracted by 1, the rightmost bit with a value of 1 will become 0, and all the bits on the right will become 1.

2) The function of each execution of X & (x-1) is to remove the last bit 1 of the binary number corresponding to X. Therefore, the number of cycles is the number of 1 in the binary number corresponding to X when “X” is equal to 0.

How to solve the number of zeros in binary system

int CountZeroBit(int num)
{
    int count = 0;
    
    while (num + 1)
    {
        count++;
        num |= (num + 1);    // algorithm transition
    }
    return count;
}
 
int main()
{
    int value = 25;
    int ret = CountZeroBit(value);
    Printf (% d's binary bits have the number of zeros% D, value, RET));
    system("pause");
    return 0;
}

Swap the values of two variables without using the third variable. That is, a = 3, B = 5, after exchange, a = 5, B = 3;

There are two solutions, one is arithmetic, the other is XOR.

a = a + b;
b = a - b;
a = a - b; 
a = a^b;//  Only for int, char
b = a^b;
a = a^b;
or
a ^= b ^= a;

Given an integer variable a, write two pieces of code. The first is to set bit 3 of a, and the second is to clear bit 3 of A. In the above two operations, keep the other bits unchanged.

#define BIT3 (0x1<<3) 
static int a; 
void set_bit3(void) 
{ 
    a |= BIT3; 
} 
void clear_bit3(void) 
{ 
    a &= ~BIT3; 
} 

Containers and algorithms

What’s the difference between map and set? How is the separation realized?

Both map and set are associated containers of C + +, and their underlying implementation is red black tree(RB-Tree)。

RB tree also provides various operation interfaces opened by map and set, so almost all the operation behaviors of map and set are just transferring the operation behaviors of Rb tree.

The difference between map and set is that

The elements in the map arekey-value(key value pair) pair:Keywords play an index roleThe value represents the data associated with the index; In contrast, set is a simple set of keywords,Each element in set contains only one keyword

The iterator of set is const, so it is not allowed to modify the value of the element; Map allows you to modify value, but not key.

The reason is that map and set are based on key sorting to ensure their orderliness. If key is allowed to be modified, first we need to delete the key, then adjust the balance, then insert the modified key value and adjust the balance. This seriously destroys the structure of map and set, resulting in iterator failure. Or point to the changed position. thereforeIn STL, the iterator of set is set to const, and it is not allowed to modify the value of the iterator; The iterator of map is not allowed to modify the key value, but the value value

Map supports subscript operation while set does not.

Map can use key as the subscript. The subscript operator of map takes the key as the subscript to perform the search. If the key does not exist, insert a key with the key and mapped_ The default value of type is added to the mapSubscript operator [] should be used with caution in map application,const_ Map can’t be used. You just want to determine whether a key value exists, and you shouldn’t use it when you don’t want to insert elements_ Type has no default value and should not be used. If find can solve the problem, use find as much as possible.

What is the function of STL allocator?

STL allocator is used to encapsulate the underlying details of STL container in memory management. In C + +, the memory configuration and release are as follows:

New operation is divided into two stages: (1) call: operator new to configure memory( 2) Call object constructor to construct object content

The delete operation is divided into two stages: (1) calling the object function( 2) Delete: operator delete to free memory

For precise division of labor, STL allocator distinguishes two stages of operation: memory configuration is in charge of alloc:: allocate() and memory release is in charge of alloc:: deallocate(); Object construction is in the charge of:: construct(), and object decomposition is in the charge of:: destroy().

At the same time, in order to improve the efficiency of memory management and reduce the memory fragmentation caused by applying for small memory, SGI STL adopts two-level configurator. When the allocated space size exceeds 128B, the first level configurator will be used; When the allocated space size is less than 128B, the second level space configurator will be used. The first level allocator uses malloc (), realloc (), free () functions to allocate and release memory space, while the second level allocator uses memory pool technology to manage memory through free linked list.

How do STL iterators delete elements?

For the sequence container vector, deque, after using erase (itertor), the iterator of each element behind will be invalid, but each element behind will move forward a position, but erase will return the next valid iterator;

For the associated container map set, after using erase (iterator), the iterator of the current element is invalid, but its structure is red black tree. Deleting the current element will not affect the iterator of the next element, so before calling erase, record the iterator of the next element.

For list, it uses memory allocated discontinuously, and its erase method will return the next valid iterator, so both of the above two correct methods can be used.

How to store map data in STL?

Red black tree. The underlying structure of unordered map is a hash table

Map and unordered in STL_ What’s the difference?

Map is implemented by using red black tree at the bottom, unordered_ Map is a new container added in C + + 11 standard. Its bottom layer is to use hash table to complete the mapping function. Map is to judge whether the elements are the same according to operator < compare, and compare the size of the elements, and then select the appropriate location to insert into the tree. Therefore, if the map is traversed (middle order traversal), the output result is ordered. The order is to sort according to the size defined by the operator.

And unordered_ Map is to calculate the hash value of the element, and judge whether the elements are the same according to the hash value. So, for unordered_ Map traversal, the result is out of order.

When using map, you need to define operator for key. And unordered_ The use of map needs to define hash_ The value function is overloaded with operator = =. For built-in types, such as string, you don’t have to worry about these. You can use the default. For a custom type to make a key, you need to overload the operator < or hash_ Value () is lost.

So it’s best to use unordered when you don’t need the results sorted_ Map, the efficiency of insert delete and query is higher than map.

What is the difference between vector and list?

  1. The underlying implementation of vector is array; A list is a two-way linked list.
  2. Vector supports random access, but list does not.
  3. Vector is sequential memory, list is not.
  4. The insertion and deletion of vector in the intermediate node will result in memory copy, but list will not.
  5. The vector allocates the memory at one time, and when the memory is not enough, it will expand twice; Each time a new node is inserted into the list, a memory request is made.
  6. The random access performance of vector is good, but the insert and delete performance is poor; List random access performance is poor, insert delete performance is good.

What is the function of iterators in STL? Why iterators with pointers?

1. Iterator

Iterator pattern, also known as cursor pattern, is used to provide a method to access elements in an aggregate object sequentially without exposing the internal representation of the object. In other words, it may be easier to understand that iterator pattern is a pattern applied to aggregate objects. By using this pattern, we can access the elements in aggregate objects in a certain order (provided by iterator) without knowing the internal representation of objects.

Due to the above characteristics of iterator pattern: coupling with aggregate objects, its wide application is limited to a certain extent. Generally, it is only used for the underlying aggregation support classes, such as STL’s list, vector, stack and ostream_ Iterator and so on.

2. The difference between iterator and pointer

Iterators are not pointers, they are class templates that behave like pointers. He just simulated some functions of pointer, overloaded some operators of pointer – >, *, + +, — and so on. Iterator encapsulates pointer, which is an object that “can traverse all or part of the elements in STL (Standard Template Library) container”. In essence, iterator encapsulates native pointer, which is a lift of pointer concept and provides a higher level behavior than pointer. It is equivalent to a kind of intelligent pointer. It can implement different + + according to different types of data structures, –And so on.

The iterator returns the object reference instead of the value of the object, so cout can only output the value after the iterator uses the * value, not directly output itself.

3. Causes of iterators

The way to access iterator class is to abstract the access logic of different collection classes, so that the internal structure of the collection is not exposed and the collection can be iterated.

What is the principle of epoll?

Call order:

int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);

First, create an epoll object, and then use epoll_ CTL operates on the object and adds the description that needs to be monitored. For example, the description will be in epoll_ The event structure forms a red black tree, which is then blocked in epoll_ When an event occurs on a FD, the kernel will put its corresponding structure into a linked list and return the linked list with the event.

What is the difference between restore and reserve in STL?

Change the number of elements in the current container (size ()), eg: vectorv; v.resize(len); The size of V becomes len. If the original size of V is smaller than len, the container adds (len size) elements with the value of
The default value is 0_ back(3); After that, 3 is placed at the end of V, that is, the subscript is len, and the container size is len + 1;

If the value of reserve (len) is greater than the current capacity (), a space that can store len objects will be reallocated, and then the first v.size () objects will be copied through the copy constructor to destroy the previous memory;

Class and data abstraction

Access rights of class members in C + +?

C + + controls the access rights of member variables and member functions through three keywords: public, protected and private. They represent public, protected and private respectively, which are called member access qualifiers. Within a class (within the code that defines the class), whether members are declared public, protected, or private, they can access each other without access restrictions. Outside the class (outside the code that defines the class), members can only be accessed through objects, and only members with public attributes can be accessed through objects, not members with private and protected attributes

What is the difference between struct and class in C + +?

In C + +, classes can be defined with struct and class, both of which can be inherited. The difference is: the default inheritance permission and default access permission of structural are public, while the default inheritance permission and default access permission of class are private. In addition, class can also define template class parameters, such as template.

Can reference data members be defined in C + + classes?

Yes, it must be initialized through the member function initialization list.

What is object oriented and generic programming?

  1. Object oriented programming, referred to as OOP, is a programming idea. OOP takes object as the basic unit of program, an object contains data and functions to operate data.
  2. Process oriented programming regards a computer program as a set of commands, that is, the sequential execution of a group of functions. In order to simplify the program design, the process oriented function is further divided into sub functions, that is, the large function is cut into small functions to reduce the complexity of the system.
  3. Generic programming: parameterize types to facilitate programmers to code.
    Type parameterization: the program (algorithm) can be abstracted from the logical function, and the type of the object (data) to be processed can be passed as a parameter.

What is a right value reference and what is the difference between a right value reference and a left value reference?

The concept of left value and right value

Lvalue: can take address or named object / variable for expression. A persistent object that still exists after the end of an expression.

Right value: can’t take address for expression or anonymous object. A temporary object that no longer exists at the end of an expression.

The difference between right value reference and left value reference

  1. Left values are addressable, while right values are not.
  2. Left value can be assigned, right value can not be assigned, it can be used to assign left value.
  3. The left value is changeable, while the right value is immutable (only applicable to basic types, and the right value reference of user-defined types can be changed through member functions).

The destructor can be virtual, but the constructor can’t. why?

Constructors cannot be declared as virtual functions, destructors can be declared as virtual functions, and sometimes must be declared as virtual functions. It is not recommended to call virtual functions in constructors and destructors.

The reason why constructors cannot be declared virtual is because:

The main meaning of virtual function is that it is inherited by derived class to produce polymorphism. In the constructor of the derived class, the compiler will add the code to construct the base class. If the constructor of the base class uses parameters, the derived class will use its constructor
The initialization list of numbers must give parameters for the base class. That’s why. Virtual function means to open dynamic binding, and the program will select the method to be called according to the dynamic type of the object. However, when the constructor is running, the dynamic type of the object is not complete, and there is no way to determine what type it is, so the constructor cannot be dynamically bound( Dynamic binding is based on the dynamic type of the object rather than the function name. Before calling the constructor, the object does not exist at all. How can it be dynamically bound

Which class member functions do C + + hollow classes generate by default?

By default, C + + hollow class will produce the following six functions: default constructor, copy constructor, destructor, assignment operator overloaded function, address operation overloaded function, const address operator overloaded function, etc.

class Empty
{
  public:
  Empty(); //  Default constructor 
  Empty( const Empty& ); //  copy constructor 
  ~Empty(); //  Destructor
  Empty& operator=( const Empty& ); //  Assignment Operators 
  Empty* operator&(); //  address-of operator 
  const Empty* operator&() const; //  Address operator const
};

object-oriented

What’s the difference between object oriented and process oriented?

There are four differences between object-oriented and process oriented

1) The starting point is different

Object oriented uses the conventional way of thinking to deal with the problems in the objective world, and emphasizes that the “action” in the problem-solving field is directly mapped to the interface between objects. Process oriented emphasizes the abstraction and modularization of the process, which is to construct or deal with the problems of the objective world with the process as the center.

2) Different levels of logic

Object oriented uses computer logic to simulate the physical existence in the objective world, takes the set class of objects as the unit to deal with problems, and makes the computer world as close to the objective world as possible, so as to make the way of dealing with problems more clear and direct. Object oriented uses the hierarchical structure of classes to reflect the inheritance and development between classes. The basic unit of process oriented problem processing is the module that can express the process clearly and accurately. The hierarchical structure of the module is used to summarize the relationship and function between the modules, and the objective world problems are abstracted into the process that can be processed by the computer.

3) Data processing mode is different from control program mode

Object oriented encapsulates data and corresponding code as a whole. In principle, other objects can’t modify their data directly, that is, the modification of objects can only be completed by their own member functions. The control program is activated and run by “event driven”. Process oriented is to process the data directly through the program, and the results can be displayed after the processing. In the control mode, the program is called or returned according to the design, and it can’t navigate freely. There are the relationships between the control and controlled modules, and between the transfer and called modules.

4) Analysis design is different from code conversion

Object oriented runs through the analysis, design and coding of software life cycle, which is a smooth process. From analysis to design and then to coding, it adopts consistent model representation, and realizes a seamless connection. Process oriented emphasizes the rule-based transformation among analysis, design and coding, which runs through the analysis, design and coding of software life cycle and realizes a kind of seamless connection.

What are the basic characteristics of object oriented?

Object oriented programming has four basic characteristics

1) Abstract: it is to ignore the aspects of a topic that have nothing to do with the current goal, so as to pay more attention to the aspects related to the current goal. Abstract does not intend to understand all the problems, but just choose part of them, not part of the details. Abstract includes two aspects, one is process abstract, the other is data abstract.

Process abstraction means that any operation with clearly defined function can be regarded as a single entity by users, although this operation may be completed by a series of lower level operations. Data abstraction defines the data type and the operations imposed on the object of this type, and limits the value of the object, which can only be modified and observed by using these operations.

2) Inheritance: This is a hierarchical model that joins classes and allows and encourages class reuse. It provides a way to express commonalities explicitly. A new class of object can be derived from an existing class. This process is called class inheritance. The new class inherits the characteristics of the original class. The new class is called the derived class (subclass) of the original class, while the original class is called the base class (parent class) of the new class.

Derived classes can inherit methods and instance variables from their base classes, and classes can modify or add new methods to make them more suitable for special needs. This also reflects the relationship between the general and the special in nature. Inheritance solves the problem of software reusability.

3) Encapsulation: it is to surround the process and data, and the data can only be accessed through the defined interface. Object oriented computing begins with the basic concept that the real world can be described as a series of completely autonomous, encapsulated objects that access other objects through a protected interface. Once the properties of an object are defined, it is necessary to determine the visibility of these properties, that is, which properties are visible to the external world and which are used to represent the internal state.

At this stage, the interface of the object is defined. In general, direct access to the actual representation of an object should be prohibited, and the object should be accessed through the operation interface, which is called information hiding. Encapsulation ensures the independence of the module and makes it easier to maintain and modify the program. The modification of the application is limited to the inside of the class, so the impact of the application modification can be minimized.

4) Polymorphism: allows different objects to respond to the same message. For example, the same copy paste operation has different effects in word processing programs and drawing programs. Polymorphism includes parametric polymorphism and inclusion polymorphism. Polymorphic language has the advantages of flexibility, abstraction, behavior sharing and code sharing, which solves the problem of the same name of application function.

What is deep copy? What is shallow copy?

Deep copy is a complete copy. All members in two objects are independent, and the member objects in the member objects are also independent.

Some member variables in the shallow copy may be shared. If the deep copy is not thorough enough, it is a shallow copy.

What is friendship?

If you want to access private members of an object elsewhere, you can only access them indirectly through the interface (member function) provided by the class. This can bring the advantage of data hiding and the expansion of program in the future, but it will also increase the trouble of program writing.

C + + is developed from the structured C language, which needs to take care of the habits of structured design programmers. Therefore, the access scope of private members should not be restricted too much.

C + + designers think that if some programmers are really afraid of trouble and want to directly access the private members of the object outside the member function of the class, it’s better to make a little compromise to meet their wishes. This is also a compromise between immediate interests and long-term interests. Therefore, C + + has been developedFriendIt’s a new concept. For example, this is equivalent to saying: friends are trustworthy, so you can disclose some of your privacy to them.

Friends provide a mechanism for ordinary functions or class member functions to access private or protected members in another class. That is to say, there are two forms of friends

(1) Friend function: a common function to access a private or protected member of a class.

(2) Friend class: member functions in class a access private or protected members in class B.

Can the constructor / destructor of the base class be inherited by the derived class?

The constructor destructor of a base class cannot be inherited by a derived class.

The constructor of the base class cannot be inherited by the derived class. The derived class needs to declare its own constructor. When designing the constructor of derived class, we should not only consider the initialization of data members added by derived class, but also consider the initialization of data members of base class. When you declare the constructor, you only need to initialize the new members in this class. To initialize the inherited base class members, you need to call the base class constructor.

The destructor of the base class cannot be inherited by the derived class. The derived class needs to declare its own destructor. The declarative method is the same as the destructor of the general class (when there is no inheritance relationship). It does not need to explicitly call the destructor of the base class, and the system will automatically call it implicitly. It should be noted that the calling order of destructors is opposite to that of constructors.

What’s the difference between initialization list and constructor initialization?

The constructor initialization list starts with a colon, followed by a comma separated list of data members, each followed by an initializer in parentheses. For example:

Example:: example(): ival (0), dval (0.0) {} // ival and dval are two data members of the class

The above example is similar to the following constructor without initializing the list:

Example::Example()  
{      
  ival = 0;      
  dval = 0.0; 
} 

Indeed, the results of these two constructors are the same. But the difference is: the constructor above (using the constructor of the initialization list) shows the members of the initialization class; Constructors that do not use the initialization list assign values to the members of the class and do not initialize the display.

Initialization and assignment are not very different for members of built-in types, like any of the above constructors. But sometimes you have to use a constructor with an initialization list:

  1. A member type is a class without a default constructor. If no display initializer is provided, the compiler implicitly uses the default constructor of the member type. If the class does not have a default constructor, the compiler will fail to attempt to use the default constructor.
  2. Const member or member of a reference type. Because const objects or reference types can only be initialized, they cannot be assigned values.

In C + +, which cases can only use initialization list instead of assignment?

The constructor initialization list starts with a colon, followed by a comma separated list of data members, each followed by an initializer in parentheses. For example, e xample:Example ival (O, DVA (0.0) {}, where ival and DVA are two data members of the class.

In C + + language, the principle of assignment is different from that of initialization list. Assignment is to delete the original value and give a new value. Initialization list opens up space and initialization is completed at the same time, and a value is given directly

Therefore, in C + +, the use of assignment and initialization list is not the same. There are three cases that can only use initialization list but not assignment

  1. When there are const (constant) and reference (Reference) member variables in a class, they can only be initialized and cannot be assigned values. Constants cannot be assigned values, they can only be initialized, so they must be completed in the initialization list. C + + references must also be initialized, so they must be completed in the initialization list.
  2. The derived class initializes its own member in the constructor, and initializes the inherited base class members. When the base class does not have a default constructor, it calls the constructor of the base class in the constructor initialization list of the derived class.
  3. If the member type is a class without a default constructor, you can only use the initialization list. If no explicit initialization is provided, the compiler implicitly uses the default constructor of the member type, and the compiler’s attempt to use the default constructor will fail

What is the initialization order of class member variables?

  1. When a member variable is initialized with an initialization list, it has nothing to do with the order of initializing the member list in the constructor, but only with the order of defining the member variable. Because the initialization order of member variables is related to the order of variables in memory, and the order of variables in memory is determined by the definition order of variables as early as compile time. This is described in detail in effective c + +.
  2. If the initialization list is not used for initialization, the initialization in the constructor is related to the position of the member variable in the constructor.
  3. Note: class members cannot be initialized when they are defined
  4. Note: const member constants in a class must be initialized in the constructor initialization list.
  5. Note: static member variables in a class must be initialized outside the class.
  6. The initialization order of static variables is that the static variables of the base class are initialized first, and then their derived classes. Until all static variables are initialized. It should be noted that the initialization of global variables and static variables is not in order. It’s not hard to understand. In fact, static variables and global variables are placed in the common memory area. Static variables can be understood as global variables with scope. After all initialization, the main function will be called. If the constructor of a class is executed, the member variables of the base class will be initialized first.

When a class is a member variable of another class, how to initialize it?

The sample procedure is as follows:

class ABC 
{
public:
    ABC(int x, int y, int z); 
private : 
    int a; 
    int b; 
    int c;
};
 
class MyClass 
{
public:
    MyClass():abc(1,2,3)
    {
        
    } 
 
private:
ABC abc;
};

In the above example, because ABC has an explicit constructor with parameters, it cannot rely on the compiler to generate a parameterless constructor, so it must use the initialization list: ABC (1,2,3) to construct ABC objects.

Can C + + design and implement a class that cannot be inherited?

The keyword final is defined in Java, and the class modified by final cannot be inherited. However, there is no final keyword in C + +, so it will take some effort to achieve this requirement.

The first thought is that in C + +, the constructor of subclass will automatically call the constructor of parent class. Similarly, the destructor of the subclass automatically calls the destructor of the parent class. To prevent a class from being inherited, we only need to define its constructor and destructor as private functions. So when a class attempts to inherit from it, it will inevitably lead to compilation errors due to calling constructors and destructors.

But the constructor and destructor of this class are private functions. How can we get the instance of this class? We can create and release instances of classes by defining statics.
Based on this idea, we can write the following code:

/// // Define a class which can't be derived from  /// class FinalClass1
{
public :      
static FinalClass1* GetInstance()     
 {          
   return new FinalClass1;    
  }        
static void DeleteInstance( FinalClass1* pInstance)    
  {            
 delete pInstance;         
   pInstance = 0;     
 }  
 private :      
 FinalClass1() {}     
 ~FinalClass1() {}
};

This class can’t be inherited, but I always think it’s different from ordinary classes, and it’s a little inconvenient to use. For example, we can only get instances on the heap, not on the stack. Can we implement a class that has the same usage as a general class except that it cannot be inherited? There are always ways, but it takes some skill. Please see the following code:

 /// // Define a class which can't be derived from  /// template <typename T> class MakeFinal
{     
  friend T;
 private :     
  MakeFinal() {}    
  ~MakeFinal() {}
};   
class FinalClass2 :
 virtual public MakeFinal<FinalClass2>
{
public :      
 FinalClass2() {}  
    ~FinalClass2() {}
};

This class is no different from other classes. You can create instances on the stack or on the heap. Although classMakeFinal <FinalClass2>The constructor and destructor are all private, but because class FinalClass2 is its friend function, it is called in FinalClass2.MakeFinal <FinalClass2>Neither the constructor nor the destructor of will cause compilation errors. But when we try to inherit a class from finalclass2 and create an instance of it, it’s different from compiling.

class Try : public FinalClass2
{
 public :    
   Try() {}   
   ~Try() {}
};    Try temp; 

Because the class finalclass2 is derived from theMakeFinal <FinalClass2>Virtual inheritance, when calling try’s constructor, will directly skip finalclass2 and call directlyMakeFinal <FinalClass2>The constructor for. Unfortunately, try is notMakeFinal <FinalClass2>Cannot call its private constructor.

Based on the above analysis, any class that attempts to inherit from finalclass2 will cause compilation errors once it is instantiated, so finalclass2 cannot be inherited. This meets our design requirements.

Constructor has no return value, so how to know whether the object is constructed successfully?

The “construction” here not only refers to the memory allocation of the object itself, but also refers to the initialization operation (such as opening a file, connecting to a database, etc.) when the object is created.

Because the constructor does not return a value, the only way to notify an object of construction failure is to throw an exception in the constructor. Throwing an exception in the constructor will cause the destructor of the object not to be executed. When the object is partially constructed, the constructed sub objects will be destructed in reverse order.

What are the differences among public inheritance, protected inheritance and private inheritance?

Public inheritance, protected inheritance and private inheritance are three common inheritance methods.

  1. public inheritance

For subclass objects, when using public inheritance, the visibility of base class members to subclass objects is the same as that of general class members. Public members are visible, while other members are invisible.

For subclasses, the public and protected members of the base class are visible; When the public members and protected members of the base class are members of the derived class, they maintain the original visibility (whether the public members of the base class are public in the subclass, or whether the protected members of the base class are protected in the subclass); Private members of the base class are not visible, private members of the base class are still private, and subclasses are not accessible.

  1. Protection of inheritance

The feature of protected inheritance is that all public members and protected members of the base class become protected members of the derived class, and can only be accessed by its derived class member functions or friends. Private members of the base class are still private. From this we can see that all members of the base class are invisible to the objects of the subclass.

  1. Private succession

The characteristic of private inheritance is that both the public and protected members of the base class are private members of the derived class and cannot be accessed by subclasses of the derived class.

Does C + + provide functions with default parameters?

C + + can define default parameter values for functions. The default parameter is used automatically when no argument corresponding to the formal parameter is specified in the function call.

Syntax and use of default parameters:

(1) When a function is declared or defined, the parameter is assigned directly, which is the default parameter.

(2) When a function is called, some or all of the parameters are omitted. The default parameters can be used instead.

Usually, when a function is called, the corresponding arguments should be given for each parameter of the function. For example:

void delay(int loops=1000);// Function declaration 
 
Void delay (int loops) // function definition 
{
    if(loops==0)
    {
        return;
    }
    for(int i=0;i<loops;i++)
        ;
}

In the above example, if loops in the delay() function is defined as the default value of 1000, then whenever the delay() function is called in the future, there is no need to assign a value to loops, and the program will automatically treat it as the value of 1000. For example, when the delay (2500) call is executed, the parameters of loops are explicit and set to 2500; When delay() is executed, loops will take the default value of 1000.

The default parameter is provided in the function declaration. When there is a declaration and a definition, the default parameter is not allowed in the definition. If the function has only one definition, the default parameters can appear in the function definition. For example:

oid point(int=3,int=4);// The default value is given in the declaration 
 
Void point (int x, int y) // no default value is allowed in the definition 
{
    cout<<x<<endl;
    cout<<y<<endl;
}

If a group of overloaded functions (possibly with default parameters) are allowed to be called with the same number of arguments, the ambiguity of the call will be caused. For example:

void func(int);// One of the overloaded functions 
void func(int,int=4);// Overloaded function 2 with default parameters 
void func(int=3,int=4);// Overload function 3 with default parameters 
func(7);// Error: which of the three overloaded functions are called? 
func(20,30);// Error: which of the following two overloaded functions is called?

virtual function

What is a virtual function?

When a pointer to a base class operates its polymorphic class objects, it can call its corresponding function according to the different class objects it points to. This function is a virtual function.

Function of virtual function: after the virtual function is defined in the base class, the virtual function can be redefined in the derived class, and the function with the same name in the base class and different derived classes can be dynamically selected and called in the running phase of the program through the base class pointer or reference( If a virtual function is not redefined in a derived class, it inherits the virtual function of its base class.)

The following is an example program of virtual function:

#include "stdafx.h"
#include<iostream> 
using namespace std;
 
class Base
{
public:
    Virtual void print() // parent virtual function
    {
        printf("This is Class Base!\n");
    }
};
 
class Derived1 :public Base
{
public:
    Void print() // subclass 1 virtual function
    {
        printf("This is Class Derived1!\n");
    }
};
 
class Derived2 :public Base
{
public:
    Void print() // subclass 2 virtual function
    {
        printf("This is Class Derived2!\n");
    }
};
 
int main()
{
    Base Cbase;
    Derived1 Cderived1;
    Derived2 Cderived2;
    Cbase.Print();
    Cderived1.Print();
    Cderived2.Print();
 
    cout << "---------------" << endl;
    Base *p1 = &Cbase;
    Base *p2 = &Cderived1;
    Base *p3 = &Cderived2;
    p1->Print();
    p2->Print();
    p3->Print();
}
 
/*
Output results:
This is Class Base!
This is Class Derived1!
This is Class Derived2!
---------------
This is Class Base!
This is Class Derived1!
This is Class Derived2!
*/

It should be noted that although virtual functions are very easy to use, not all functions need to be defined as virtual functions when using virtual functions, because there is a cost to implement virtual functions. When using virtual functions, we need to pay attention to the following aspects:

(1) We only need to use the keyword virtual in the class body of the declared function to declare the function as a virtual function, but we do not need to use the keyword virtual when defining the function.

(2) When a member function in the base class is declared as a virtual function, the function with the same name in the derived class automatically becomes a virtual function.

(3) Non class member functions cannot be defined as virtual functions, global functions and static member functions and constructors in class member functions cannot be defined as virtual functions, but destructors can be defined as virtual functions.

(4) The destructor of the base class should be defined as a virtual function, otherwise it will cause a memory leak. The base class destructor does not declare virtual. When the base class pointer points to a derived class, the delete pointer does not call the derived class destructor. If there is virtual, the derived class is called first, and then the base class is called.

How to realize polymorphism in C + +?

Polymorphism is realized by virtual function in C + +. The essence of virtual function is to access the function defined by derived class through base class pointer. Each class containing a virtual function has a virtual function table pointer inside its instance object. The virtual function table pointer is initialized to the memory address of the virtual function table of this class. Therefore, in the program, no matter how the object type is converted, the virtual function table pointer inside the object is fixed, so that the object function can be called dynamically. This is the principle of C + + polymorphism.

What is pure virtual function?

Pure virtual function is a special kind of virtual function, and its format is generally as follows

Class < class name >
{
    Virtual() function return value type virtual function name (formal parameter table) = 0;
    ...
};
Class < class name >

Because in many cases, the base class can not give a meaningful implementation of the virtual function, we can only leave the implementation of the function to the derived class. For example, as a base class, animals can derive subclasses such as tigers and peacocks, but it is unreasonable for animals to generate objects. At this time, functions in animal classes can be defined as pure virtual functions. If there are pure virtual functions in the base class, then the pure virtual functions must be implemented in subclasses, otherwise subclasses will not be instantiated or polymorphic.

A class with pure virtual functions is called an abstract class, which cannot generate objects. Pure virtual functions are never called. They are mainly used to manage subclass objects.

What function cannot be declared virtual?

Common functions that cannot be declared as virtual functions are: ordinary functions (non member functions); Static member function; Inline member function; Constructor; Friend function.

1. Why C + + does not support ordinary functions as virtual functions?
Ordinary functions (non member functions) can only be overloaded and cannot be overridden. It is meaningless to declare them as virtual functions. Therefore, the compiler will bind functions at compile time.

2. Why C + + doesn’t support constructor as virtual function?
The reason is very simple, mainly from the perspective of semantics, so it is not supported. Because constructors are generated to explicitly initialize object members, however, virtual function is mainly used to correctly handle objects without fully understanding the details. In addition, the virtual function generates different actions in different types of objects. Now the object has not been generated. How to use the virtual function to complete the action you want to complete( This is the typical paradox

3. Why C + + doesn’t support inline member functions as virtual functions?
In fact, it’s very simple. The purpose of inline function is to expand directly in the code and reduce the cost of function call. The purpose of virtual function is to enable the object to perform its own actions accurately after inheritance, which is impossible to unify( In addition, the inline function is expanded at compile time, and the virtual function can be dynamically bound at run time

4. Why does C + + not support static member functions as virtual functions?
This is also very simple. Static member functions only have one code for each class. All objects share this code, and there is no need for dynamic binding.

5. Why C + + doesn’t support friend function as virtual function?
Because C + + does not support the inheritance of friend functions, there is no virtual function for functions without inheritance features.

How to prevent a class from being instantiated in C + +?

In C + +, you can prevent a class from being instantiated by using abstract classes or declaring the constructor as private. Abstract class can’t be instantiated because it can’t represent a kind of concrete things. It’s an abstraction of the common characteristics of a variety of concrete things with similarity. For example, as a base class, animals can derive subclasses such as tigers and peacocks, but it is unreasonable for animals to generate objects themselves.

epilogue

If you see good information on the Internet, or encounter knowledge points in the written interview, you can contact me and I will sort them out for you. If there is any error or inappropriate information, please contact the author in time.

I stayed up late to sort out all these contents. I’m still revising my big paper recently, and there are a lot of things. It’s not easy to create. Don’t forget to click “fabulous“With my support, I didn’t stay up late for nothing, which is worthy of my hair.

Finally, drop the GitHub link( https://github.com/ZhongYi-Li…

Recommended Today

High concurrency and multithreading

1、 What is high concurrency High concurrency is a problem encountered in the process of system operation“A large number of operation requests are encountered in a short time”The situation mainly occurs inA large number of requests are received in web system(e.g. ticket snatching of 12306; Tmall double 11. The occurrence of this situation will cause […]