C++ 30 common interview questions (with answers)

For multi-dimensional arrays, C++/C does not simply convert to pointers of the same type as one-dimensional arrays, but converts to equivalent array pointers . For example, int a[m][n] is converted to int (*a)[n] , which means that a is a pointer to a one-dimensional array, and the one-dimensional array has n elements, and a is the first one that points to the original array. The pointer of one row, a+1 is the pointer to the second row, and so on. The following four expressions are equivalent:
 

(1) a[i][j]
(2) *(a[i] + j)
(3) (*(a+ i))[j]
(4) *(*(a+ i) + j)
 

What can a derived class not inherit from a base class?

Constructors, destructors, assignment operators, and friend functions cannot be inherited.

1.new, delete, malloc, free relationship

delete will call the object's destructor , and new corresponding to free will only release the memory, and new will call the constructor . malloc and free are standard library functions of C++/C language, and new/delete are C++ operators . They can be used to apply for dynamic memory and release memory. For objects of non-internal data types, malloc/free alone cannot meet the requirements of dynamic objects. The object must automatically execute the constructor when it is created, and the object must automatically execute the destructor before it dies. Since malloc/free is a library function rather than an operator, it is not within the control of the compiler, and the task of executing the constructor and destructor cannot be imposed on malloc/free. Therefore, the C++ language needs an operator new that can complete dynamic memory allocation and initialization, and an operator delete that can complete cleanup and release of memory. Note that new/delete is not a library function.

2. The difference between delete and delete []

delete will only call the destructor once, and delete[] will call the destructor of each member. There is a more detailed explanation in More Effective C++: "When the delete operator is used in an array, it calls the destructor for each array element, and then calls operator delete to release the memory." Delete is matched with new, delete [] Matching with new []

MemTest *mTest1=new MemTest[10];

MemTest *mTest2=new MemTest;

Int *pInt1=new int [10];

Int *pInt2=new int;

delete[]pInt1; //-1-

delete[]pInt2; //-2-

delete[]mTest1;//-3-

delete[]mTest2;//-4-

Report an error at -4-.

This means that for the built-in simple data types, delete and delete[] functions are the same. For custom complex data types, delete and delete[] cannot be used mutually. delete[] deletes an array, delete deletes a pointer. Simply put, the memory allocated with new is deleted with delete; the memory allocated with new[] is deleted with delete[]. delete[] will call the destructor of the array element. There is no destructor for internal data types, so the problem is not big. If you do not use parentheses when using delete, delete will assume that it points to a single object, otherwise, it will assume that it points to an array.

3. What are the properties of C++ (object-oriented features)

Encapsulation, inheritance and polymorphism.

4. Should the destructor of the parent be called when the subclass is destructed?

The order of the destructor call is the destruction of the derived class first and then the destruction of the base class, which means that when the destructor of the base class is called, all the information of the derived class has been destroyed. When defining an object, call the constructor of the base class first, and then call the constructor of the derived class; when destructuring, the opposite is true: first call the destructor of the derived class, then call the destructor of the base class.

5. Polymorphism, virtual function, pure virtual function

Polymorphism: Different actions are generated when different objects receive the same message. The polymorphism of C++ is embodied in two aspects of operation and compilation: the polymorphism of the program is reflected through inheritance and virtual functions;

Polymorphism is reflected in the overloading of functions and operators when the program is compiled;

Virtual function : a member function prefixed with the keyword virtual in the base class . It provides an interface interface. It is allowed to redefine the virtual function of the base class in the derived class.

The role of pure virtual function : reserve a function name for its derived class in the base class so that the derived class can define it as needed. Exist as an interface. Pure virtual functions do not have the functions of functions and generally cannot be called directly.

Pure virtual functions inherited from the base class are still virtual functions in derived classes. If there is at least one pure virtual function in a class, then this class is called an abstract class (abstract class).

Abstract classes include not only pure virtual functions, but also virtual functions . Abstract classes must be used as base classes to derive other classes, and cannot be used to directly create object instances. However, pointers to abstract classes can still be used to support runtime polymorphism.

6. Find the return value of the following function (Microsoft)

int func(x) 

int countx = 0; 

while(x) 

countx ++; 

x = x&(x-1); 

return countx; 

Assume x = 9999. Answer: 8

Idea: Convert x to binary system and see the number of ones contained.

7. What is "quotation"? What issues should be paid attention to when affirming and using "quotations"?

Answer: The reference is the "alias" of a target variable . The effect of the operation on the reference is exactly the same as the direct operation on the variable. When declaring a reference, remember to initialize it. After the reference is declared, it is equivalent to the target variable name has two names, namely the original name of the target and the reference name, and the reference name cannot be used as an alias for other variable names. Declaring a reference is not a new definition of a variable. It only means that the reference name is an alias of the target variable name. It is not a data type itself, so the reference itself does not occupy storage units, and the system does not allocate storage units to the reference. Cannot create a reference to an array.

8. What are the characteristics of using "reference" as a function parameter?

(1) The effect of passing a reference to a function is the same as passing a pointer . At this time, the formal parameter of the called function becomes the actual parameter variable or an alias of the object in the original calling function. Therefore, the operation of the formal parameter variable in the called function is the corresponding target object (in the calling function). In the call function).

(2) Using reference to pass the parameters of the function, there is no copy of the actual parameter in the memory, it is a direct operation on the actual parameter; while using the general variable to pass the function parameter, when a function call occurs, it needs to allocate storage to the formal parameter For the unit, the formal parameter variable is a copy of the actual parameter variable; if the object is passed, the copy constructor will also be called. Therefore, when the data passed by the parameter is large, the efficiency and the space occupied by the reference are better than the general variable.

(3) Although the use of pointers as function parameters can also achieve the effect of using references, in the called function, storage units must also be allocated to formal parameters, and the form of "*pointer variable name" needs to be repeatedly used for calculations. This is prone to errors and poor readability of the program; on the other hand, at the call point of the calling function, the address of the variable must be used as the actual parameter. And citations are easier to use and clearer.

9. When do I need to use "frequently quoted"? 

If you want to use references to improve the efficiency of the program, but also to protect the data passed to the function from being changed in the function, you should use constant references. Often quoted declaration method: const type identifier & reference name = target variable name;

Example 1

int a ;

const int &ra=a;

ra=1; //error

a=1; //correct

Example 2

string foo( );

void bar(string & s);

Then the following expression will be illegal:

bar(foo( ));

bar("hello world");

The reason is that both foo() and "hello world" strings will produce a temporary object, and in C++, these temporary objects are of const type. Therefore, the above expression is an attempt to convert a const type object to a non-const type, which is illegal. Reference parameters should be defined as const if they can be defined as const.

10. The format, benefits and rules of using "reference" as the return value type of a function?

Format: type identifier & function name (formal parameter list and type description) {//function body}

Benefit: no copy of the returned value is produced in memory; (Note: It is for this reason that it is not advisable to return a reference to a local variable. Because as the local variable's lifetime ends, the corresponding reference is also It will fail and cause runtime error! 

Precautions:

(1) References to local variables cannot be returned. This article can refer to Item 31 of Effective C++[1]. The main reason is that local variables will be destroyed after the function returns, so the returned reference becomes a "non-referred" reference, and the program will enter an unknown state.

(2) A reference to the memory allocated by new within the function cannot be returned. This article can refer to Item 31 of Effective C++[1]. Although there is no passive destruction of local variables, but for this situation (returning a reference to the new allocated memory inside the function), it faces other embarrassing situations. For example, if the reference returned by the function only appears as a temporary variable without being assigned an actual variable, then the space pointed to by this reference (allocated by new) cannot be released, causing a memory leak.

(3) References to class members can be returned, but const is best. This principle can refer to Item 30 of Effective C++[1]. The main reason is that when the attributes of an object are associated with a certain business rule, its assignment is often related to some other attributes or the state of the object. Therefore, it is necessary to encapsulate the assignment operation in a business rule. If other objects can obtain a non-constant reference (or pointer) of the attribute, then the simple assignment of the attribute will destroy the integrity of the business rules.

(4) The function of overloading the return value of the stream operator declared as "reference":

Stream operators << and >>, these two operators are often expected to be used consecutively, for example: cout << "hello" << endl; Therefore, the return value of these two operators should be one and still support these two operations The stream reference of the symbol. Other optional solutions include: returning a stream object and returning a stream object pointer. But for returning a stream object, the program must reconstruct (copy) a new stream object, that is to say, two consecutive << operators are actually for different objects! This is unacceptable. For returning a stream pointer, the << operator cannot be used continuously. Therefore, returning a stream object reference is the only option. This only choice is very important. It illustrates the importance and irreplaceability of references. Perhaps this is the reason why the concept of reference is introduced in the C++ language. 

Assignment operator =. This operator, like the stream operator, can be used continuously, for example: x = j = 10; or (x=10)=100; the return value of the assignment operator must be an lvalue so that it can be assigned. Therefore, reference becomes the only return value option for this operator.

#include<iostream.h>

int &put(int n);

int waltz [10];

int error=-1;

void main()

{

put(0)=10; //Take the put(0) function value as the lvalue, which is equivalent to vals[0]=10; 

put(9)=20; //Take the put(9) function value as the lvalue, which is equivalent to vals[9]=20; 

cout<<vals[0]; 

cout<<vals[9];

int &put(int n)

{

if (n>=0 && n<=9 ) return vals[n]; 

else { cout<<"subscript error"; return error; }

}

(5) In some other operators, you must never return a reference: +-*/ Four arithmetic operators. They cannot return references, Item 23 of Effective C++ [1] discusses this issue in detail. The main reason is that these four operators have no side effect. Therefore, they must construct an object as the return value. The optional solutions include: returning an object, returning a reference to a local variable, returning a reference to an object allocated by new, and returning A static object reference. According to the aforementioned three rules of reference as return value, the second and third options were rejected. References to static objects also cause errors because ((a+b) == (c+d)) will always be true. So the only option left is to return an object.

11. What is the difference between structure and union?

(1). Structures and unions are composed of multiple members of different data types, but at any one time, only one selected member is stored in the union (all members share an address space), and all members of the structure are Exist (different members have different storage addresses). 

(2). Assigning values ​​to different members of the union will overwrite other members, the original member value does not exist, and the assignment of different members of the structure does not affect each other.

12. Try to write the program result:

int  a=4;

int  &f(int  x)

{    a=a+x;

      return  a;

}

int main(void)

{    int   t=5;

     cout<<f(t)<<endl;  a = 9

    f(t)=20;             a = 20

    cout<<f(t)<<endl;     t = 5,a = 20  a = 25

     t=f(t);                a = 30 t = 30

    cout<<f(t)<<endl;  }    t = 60

}

 13. What is the difference between overload and overried (some books are also called "covering")?

Common questions. By definition:

Overloading: It means that multiple functions with the same name are allowed, and the parameter lists of these functions are different (perhaps the number of parameters is different, or the parameter types are different, or both are different).

Rewrite: refers to the method of redefining the virtual function of the parent class by the subclass.

In terms of implementation principle:

Overloading: The compiler modifies the name of the function with the same name according to the different parameter list of the function, and then these functions with the same name become different functions (at least for the compiler). For example, there are two functions with the same name: function func(p:integer):integer; and function func(p:string):integer;. Then the function names modified by the compiler may look like this: int_func, str_func. The calls to these two functions are determined between the compilers and are static. In other words, their addresses are bound at compile time (early binding), so overloading has nothing to do with polymorphism!

Rewrite: Really related to polymorphism. When the subclass redefines the virtual function of the parent class, the parent class pointer dynamically calls the function belonging to the subclass according to the different subclass pointers assigned to it. Such function calls cannot be determined during compilation (call The address of the virtual function of the subclass cannot be given). Therefore, such function addresses are bound at runtime (late binding).

  

 14. In what cases can I only use the initialization list but not the assignment?

Answer: When the class contains const and reference member variables; the constructor of the base class needs to initialize the table.

15. Is C++ type safe?

Answer: No. Two pointers of different types can be coerced (using reinterpret cast). C# is type safe.

16. What code will be executed before the main function is executed?

Answer: The constructor of the global object will be executed before the main function.

17. Describe the memory allocation methods and their differences?

1) Allocate from static storage area. The memory is allocated when the program is compiled, and this memory exists during the entire running period of the program. For example, global variables, static variables.

2) Create on the stack. When the function is executed, the storage units of the local variables in the function can be created on the stack, and these storage units are automatically released when the function execution ends. The stack memory allocation operation is built into the processor's instruction set.

3) Allocation from the heap, also known as dynamic memory allocation. When the program is running, use malloc or new to apply for any amount of memory, and the programmer is responsible for when to use free or delete to release the memory. The lifetime of dynamic memory is determined by the programmer, and it is very flexible to use, but it has the most problems.

 18. Write out the comparison statement of BOOL, int, float, pointer type variable a and "zero" respectively. From "Guide to High Quality Programming"

answer:

BOOL : if ( !a ) or if(a)

int : if ( a == 0)

float : const EXPRESSION EXP = 0.000001

if ( a < EXP && a >-EXP)

pointer : if ( a != NULL) or if(a == NULL)

19. Please tell me what are the advantages of const compared with #define? From "Guide to High Quality Programming"

answer:

const function: define constants, modify function parameters, and modify function return values. The things modified by Const are subject to mandatory protection, which can prevent unexpected changes and improve the robustness of the program.

1) const constants have data types, while macro constants have no data types. The compiler can perform type safety checks on the former. For the latter, only character substitution is performed, there is no type safety check, and unexpected errors may occur in character substitution.

2) Some integrated debugging tools can debug const constants, but cannot debug macro constants.

20. Briefly describe the difference between array and pointer?

Arrays are either created in static storage (such as global arrays) or created on the stack. The pointer can point to any type of memory block at any time.

(1) Differences in modified content

char a[] = “hello”;

a[0] = ‘X’;

char *p = "world"; // Note that p points to a constant string

p[0] ='X'; // The compiler cannot find the error, it is a runtime error

(2) Use the operator sizeof to calculate the capacity (number of bytes) of the array. sizeof(p), p is the number of bytes of a pointer variable, not the memory capacity pointed to by p. There is no way for the C++/C language to know the memory capacity pointed to by the pointer unless it is remembered when requesting memory. Note that when an array is passed as a function parameter, the array automatically degenerates into a pointer of the same type.

char a[] = "hello world";

char *p = a;

cout<< sizeof(a) << endl; // 12 字节

cout<< sizeof(p) << endl; // 4 字节

Calculate the memory capacity of arrays and pointers

void Func(char a[100])

{

cout<< sizeof(a) << endl; // 4 bytes instead of 100 bytes

}

Question 21: What does int (*s[10])(int) mean? *

int (*s[10])(int) Function pointer array, each pointer points to an int func(int param) function.

Question 22: Stack memory and text constant area

           char str1[] = "abc";
  char str2[] = "abc";

  const char str3[] = "abc";
  const char str4[] = "abc";

  const char *str5 = "abc";
  const char *str6 = "abc";

  char *str7 = "abc";
  char *str8 = "abc";

  cout << (str1 == str2) << endl; //0 respectively point to their respective stack memory
  cout << (str3 == str4) << endl; //0 respectively point to their respective stack memory
  cout << (str5 = = str6) << endl;//1 points to the same address in the text constant area

  cout << (str7 == str8) << endl;//1 points to the same address in the text constant area

  The result is: 0 0 1 1

  Answer: str1, str2, str3, str4 are array variables, they have their own memory space; and str5, str6, str7, str8 are pointers, they point to the same constant area.

Question 23: Jump the program to the specified memory address

To assign a value to the absolute address 0x100000, we can use (unsigned int*)0x100000 = 1234; then what should we do if we want the program to jump to the absolute address 0x100000 for execution?


  *((void (*)( ))0x100000) ();
  First, 0x100000 must be forced into a function pointer, that is:
  (void (*)())0x100000
  and then call it:
  *((void (*)() )0x100000)();
  can be seen more intuitively with typedef:
  typedef void(*)() voidFuncPtr;
  *((voidFuncPtr)0x100000)();

Question 24: int id[sizeof(unsigned long)]; Is this correct? why?


 Answer: Correct. This sizeof is a compile-time operator, which is determined at compile-time and can be regarded as a constant related to the machine.

Question 25: What is the difference between a reference and a pointer?


[Refer to the answer]                         
1) The reference must be initialized, the pointer is not necessary.

2) The reference cannot be changed after initialization, and the pointer can change the object pointed to.

3) There is no reference to the null value, but there is a pointer to the null value.

Question 26: Comparing const and #define, what are the advantages of const? From the "Guide to High Quality Programming"
 [Reference Answer]

(1) const constants have data types , while macro constants have no data types . The compiler can perform type safety checks on the former. 'On the latter, only character replacement is performed, there is no type safety check, and unexpected errors (side effects) may occur in character replacement.

(2) Some integrated debugging tools can debug const constants, but they cannot debug macro constants.

Item 27: Complex declaration

void * ( * (*fp1)(int))[10];

float (*(* fp2)(int,int,int))(int);

int (* ( * fp3)())[10]();

What do they mean?
【standard answer】                                                           

1.void * (* (*fp1)(int))[10]; fp1 is a pointer, pointing to a function, the parameter of this function is int type, the return value of the function is a pointer, this pointer points to an array, this The array has 10 elements, and each element is a void* pointer.

2. float (*(* fp2)(int,int,int))(int); fp2 is a pointer, pointing to a function, the parameter of this function is 3 int type, the return value of the function is a pointer, this pointer Point to a function, the parameter of this function is int type, the return value of the function is float type.

3.int (* (* fp3)())[10](); fp3 is a pointer, pointing to a function, the parameter of this function is empty, the return value of the function is a pointer, this pointer points to an array, this array There are 10 elements, each element is a pointer to a function, the parameter of this function is empty, the return value of the function is int type.

Question 28: How many ways are there to allocate memory?   From "High-quality Programming Guide"

[Reference answer]

1. Allocate from static storage area . The memory is allocated when the program is compiled, and this memory exists during the entire running period of the program. For example, global variables.

2. Create on the stack . When the function is executed, the storage units of the local variables in the function can be created on the stack, and these storage units are automatically released when the function execution ends. The stack memory allocation operation is built into the processor's instruction set and is very efficient, but the allocated memory capacity is limited.

3. Allocation from the heap , also known as dynamic memory allocation. When the program is running, use malloc or new to apply for any amount of memory, and the programmer is responsible for when to use free or delete to release the memory. The lifetime of dynamic memory is determined by us. It is very flexible to use, but it has the most problems.

Question 29: The destructor of the base class is not a virtual function. What problems will it bring?

[Refer to the answer] The destructor of the derived class is not used, which will cause resource leakage.

Question 30: What is the difference between global variables and local variables? How is it achieved? How do the operating system and compiler know?

[Reference answer]

The life cycle is different:

Global variables are created and created with the main program, and destroyed when the main program is destroyed; local variables exist in local functions or even local loop bodies, so exit does not exist;

The usage is different: all parts of the global variable program can be used after declaration; local variables can only be used locally; they are allocated in the stack area. 

The operating system and the compiler know the location of the memory allocation. Global variables are allocated in the global data segment and loaded when the program starts to run. Local variables are allocated on the stack.

Guess you like

Origin blog.csdn.net/qingzhuyuxian/article/details/107938453
Recommended