A selection of 30 C++ interview questions (including analysis)

Click " C Language and CPP Programming " above, select " Follow/ Top/Star Official Account "

Dry goods benefits, the first time to deliver!

Hello everyone, my name is Tang Tang. Today I will share with you some classic C++ interview questions.

1. The relationship between new, delete, malloc, free

malloc and free are standard library functions of C/C++ language, and new/delete are C++ operators.

new calls the constructor, delete calls the object's destructor, and free just frees the memory.

Both of them can be used to allocate dynamic memory and free memory. But for objects of non-internal data types, malloc/free alone cannot meet the requirements of dynamic objects. Objects automatically execute constructors when they are created, and destructors are automatically executed before objects die. 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 the work of dynamic memory allocation and initialization, and an operator delete that can complete the work of cleaning and freeing memory. Note: new/delete are not library functions.

2. The difference between delete and delete []

delete will only call the destructor once, while delete[] will call the destructor of each member function.

It's explained in more detail in More Effective C++: "When the delete operator is used on an array, it calls the destructor for each array element and then calls operator delete to free the memory." delete is paired with new, delete [] Compatible 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: for built-in simple data types, delete and delete[] function are the same. For custom complex data types, delete and delete[] cannot be used interchangeably. delete[] deletes an array, delete deletes a pointer. In short, 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. Internal data types don't have destructors, so it's not a big problem. If you use delete without parentheses, delete will think it refers to a single object, otherwise, it will think it refers to an array.

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

Encapsulation, Inheritance and Polymorphism

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

The order of destructor calls is the destructor of the derived class first and then the destructor of the base class, that is to say, when the destructor of the base class is called, the information of the derived class has been completely destroyed. When defining an object, the base class constructor is called first, and then the derived class constructor is called; when destructing, the opposite is true: the derived class's destructor is called first, and then the base class's destructor is called.

5. Introduce polymorphism, virtual functions and pure virtual functions.

Polymorphism: Different objects take different actions when they receive the same message. The polymorphism of C++ is embodied in two aspects: running and compiling: the polymorphism when the program is running is embodied by inheritance and virtual functions; when the program is compiling, the polymorphism is embodied in the overloading of functions and operators;

Virtual function: A member function prefixed with the keyword virtual in the base class. It provides an interface interface. Allows redefinition of base class virtual functions in derived classes.

The role of pure virtual function: the name of a function is reserved in the base class for its derived class, so that the derived class can define it as needed. A pure virtual function that exists as an interface does not have the function of a function, and generally cannot be called directly.

Pure virtual functions inherited from the base class are still virtual functions in the derived class. A class is called an abstract class if it has at least one pure virtual function in it.

Abstract classes include not only pure virtual functions, but also virtual functions. An abstract class is one that must be used as a base class from which other classes can be derived, and cannot be used to create object instances directly. Runtime polymorphism is still supported using pointers to abstract classes.

Note:

Defining a function as a virtual function does not mean that the function is not implemented. It is defined as a virtual function to allow the function of the subclass to be called with the base class pointer. Defining a function as a pure virtual function means that the function is not implemented.

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 and see the number of 1s it contains

7. What is a "reference"? What issues should be paid attention to when declaring and using "reference"?

A reference is an "alias" of a target variable, and the operation on the application 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 having two names, namely the original name of the target and the reference name. The reference name cannot be used as an alias for other variable names. Declaring a reference does not mean that a variable is newly defined. It only means that the reference name is an alias of the target variable name. It is not a data type itself, because the reference itself does not occupy a storage unit, and the system does not allocate a storage unit to the reference. . A reference to an array cannot be created.

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

(1) Passing a reference to a function has the same effect as passing a pointer. At this time, the formal parameter of the called function is used as an alias of the actual parameter variable or object in the original calling function, so the operation of the formal parameter variable in the called function is to the corresponding target object (in the calling function). function) operation.

(2) The parameters of the function are passed by reference, and there is no copy of the actual parameters in the memory. It operates directly on the actual parameters; while the parameters of the function are passed by general variables, when a function call occurs, it is necessary to allocate storage to the formal parameters unit, the parameter variable is a copy of the actual parameter variable; if an object is passed, the copy constructor will also be called. Therefore, when the data passed by the parameter is large, the efficiency and space occupied by passing the parameter by reference are better than that by using the general variable.

(3) Although using a pointer as a parameter of a function can also achieve the same effect as using a reference, in the called function, a storage unit must also be allocated to the formal parameter, and the form of "*pointer variable name" needs to be used repeatedly for operations. This is error-prone and the program is less readable; on the other hand, at the call site of the calling function, the address of the variable must be used as an argument. And citations are easier to use and clearer.

9. When do you need to use "constant references"?

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

Example 1

1 int a ;
2 const int &ra=a;
3 ra=1; //错误
4 a=1; //正确

Example 2

1 string foo( ); 2 void bar(string & s);

Then the following expression would be illegal:

1 bar(foo( )); 2 bar("hello world");

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

10. What are the formats, benefits and rules for using "reference" as a function return type?

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

Benefit: No copy of the returned value is made in memory; (Note: It is for this reason that it is not advisable to return a reference to a local variable. Because with the end of the local variable lifetime, the corresponding reference is also will fail, resulting in a runtime error!

Precautions:

(1) A reference to a local variable cannot be returned. This 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 "nothing" reference, and the program will enter an unknown state.

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

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

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

Stream operators << and >>, these two operators are often expected to be used consecutively, for example: cout << "hello" << endl; so the return value of these two operators should be one that still supports these two operations A stream reference for the character. Alternative alternatives include: returning a stream object and returning a stream object pointer. But for returning a stream object, the program must re (copy) construct a new stream object, that is, two consecutive << operators are actually for different objects! This is unacceptable. The << operator cannot be used continuously for returning a stream pointer. Therefore, returning a stream object reference is the only option. This only choice is crucial, it shows the importance and irreplaceability of references, perhaps this is the reason why the concept of references was introduced in the C++ language.

The 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 continuously assigned. Therefore a reference becomes the only return value option for this operator.

1 #include<iostream>
 2 using namespace std;
 3 int &put(int n);
 4 int vals[10];
 5 int error=-1;
 6 int main()
 7 {
 8     put(0)=10; //以put(0)函数值作为左值,等价于vals[0]=10;
 9     put(9)=20; //以put(9)函数值作为左值,等价于vals[9]=20;
10     cout<<vals[0];
11     cout<<vals[9];
12     return 0;
13 }
14 int &put(int n)
15 {
16     if (n>=0 && n<=9 ) return vals[n];
17     else
18     {
19         cout<<"subscript error";
20         return error;
21     }
22 }

(5) In some other operators, but must not return a reference: +-*/ four operators. They cannot return references, which is discussed in detail in Item 23 of Effective C++ [1]. The main reason is that these four operators have no side effect, so 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, returning A static object reference. According to the aforementioned three rules of reference as return value, the 2nd and 3rd solutions are both rejected. References to static objects again 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). Both 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). For the assignment of different members of the union, other members will be rewritten, the value of the original member does not exist, and the assignment to different members of the structure does not affect each other.

12. Try to write the program result:

1 int  a=4;
 2 int  &f(int  x)
 3 {
 4     a = a + x;
 5     return  a;
 6 }
 7 int main()
 8 {
 9     int t = 5;
10     cout<<f(t)<<endl;  //a = 9
11     f(t) = 20;           //a = 20
12     cout<<f(t)<<endl;  //t = 5,a = 25
13     t = f(t);            //a = 30 t = 30
14     cout<<f(t)<<endl;  //t = 60
15     return 0;
16 }

13. What is the difference between overloading and overriding?

By definition:

Overloading: It means that multiple functions with the same name are allowed, and the parameter tables of these functions are different (maybe the number of parameters is different, the parameter type may be different, or both).

Overriding: refers to the method in which the subclass redefines the virtual function of the superclass.

In terms of implementation principle:

Overloading: The compiler modifies the names of the functions with the same name according to the different parameter lists of the functions, 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 be like this: int_func, str_func. The calls to these two functions have been determined between the compilers and are static. That is, their addresses are bound at compile time (early binding).

Rewrite: 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 a function call cannot be determined during compilation. (the address of the virtual function of the called subclass cannot be given). Therefore, such function addresses are bound at runtime (late bound).

14. In what situations can only intialization list be used instead of assignment?

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?

no. It is possible to cast (with reinterpret cast) between two pointers of different types. C# is type safe.

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

The constructor of the global object is executed before the main function.

17. Describe how memory is allocated and how they differ?

1) Allocate from static storage area. Memory is allocated when the program is compiled, and this memory exists for the entire runtime of the program. Such as global variables, static variables.

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

3) Allocate 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 is very flexible to use, but also has the most problems.

18. Write out the comparison statement between bool, int, float, pointer type variable a and "zero".

1 bool : if(!a) or if(a) 2 int : if(a == 0) 3 float : const EXPRESSION EXP = 0.000001 4 if (a < EXP && a >-EXP) 5 pointer : if(a != NULL) or if(a == NULL)

19. Please tell me what are the advantages of const compared to #define?

The role of const: defining constants, modifying function parameters, and modifying function return values. Everything modified by const is protected by 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. In the latter, only character substitution is performed, there is no type safety checking, and unexpected errors may occur during character substitution.

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

20. Briefly describe the difference between an array and a pointer?

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

(1) Differences in the revised content

1 char a[] = "hello";
2 a[0] = 'X';
3 char *p = "world"; // 注意p 指向常量字符串
4 p[0] = 'X'; // 编译器不能发现该错误,运行时错误

(2) The capacity (number of bytes) of the array can be calculated with the operator sizeof. sizeof(p), p gets the number of bytes of a pointer variable for a pointer, not the memory capacity pointed to by p. The C++/C language has no way of knowing the amount of memory pointed to by a pointer unless it is remembered when allocating memory. Note that when an array is passed as a function parameter, the array automatically degenerates to a pointer of the same type.

1 char a[] = "hello world";
 2 char *p = a;
 3 
 4 //计算数组和指针的内存容量
 5 cout<< sizeof(a) << endl; // 12 字节
 6 cout<< sizeof(p) << endl; // 4 字节
 7 
 8 //数组作为函数参数传递
 9 void Func(char a[100])
10 {
11     cout<< sizeof(a) << endl; // 4 字节而不是100 字节
12 }

21. What is the difference between a reference and a pointer?

  1. References must be initialized, pointers do not.

  2. A reference cannot be changed after it is initialized, a pointer can change the object it points to.

  3. There are no references to nulls, but there are pointers to nulls.

22. The destructor of the base class is not a virtual function, what problems will it bring?

Destructors of derived classes are not used, which will cause resource leaks.

23. What is the difference between global variables and local variables? How is it achieved? How do operating systems and compilers know about it?

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 inside local functions, even local loop bodies, etc., and exit does not exist;

Use differently:

After declaring global variables, all parts of the program can be used; local variables can only be used locally; they are allocated in the stack area.

The memory allocation locations are different:

Global variables are allocated in the global data section and loaded when the program starts running. Local variables are allocated on the stack.

24. Write a full version of the strcpy function:

If you write a standard strcpy function with a total score of 10, here are several answers with different scores:

2 minutes

void strcpy( char *strDest, char *strSrc )
{
    while( (*strDest++ = * strSrc++) != '\0' );
}

4 points

void strcpy( char *strDest, const char *strSrc )
//将源字符串加const,表明其为输入参数,加2分
{
    while( (*strDest++ = * strSrc++) != '\0' );
}

7 points

void strcpy(char *strDest, const char *strSrc)
{
    //对源地址和目的地址加非0断言,加3分
    assert( (strDest != NULL) && (strSrc != NULL) );
    while( (*strDest++ = * strSrc++) != '\0' );
}

10 points

//为了实现链式操作,将目的地址返回,加3分! 
char * strcpy( char *strDest, const char *strSrc )
{
    assert( (strDest != NULL) && (strSrc != NULL) );
    char *address = strDest;
    while( (*strDest++ = * strSrc++) != '\0' );
    return address;
}

25. Why do standard header files have structures like the following?

#ifndef __INCvxWorksh
#define __INCvxWorksh
#ifdef __cplusplus
extern "C" {
#endif
/*...*/
#ifdef __cplusplus
}
#endif
#endif /* __INCvxWorksh */

Compile macros in header files

#ifndef __INCvxWorksh
#define __INCvxWorksh
#endif

The role is to prevent repeated references.

As an object-oriented language, C++ supports function overloading, while the procedural language C does not. The names of the functions in the symbol library after being compiled by C++ are different from those in the C language. For example, suppose the prototype of a function is:

void foo(int x, int y);

The function is compiled by the C compiler with the name _foo in the symbol library, while the C++ compiler will generate names like _foo_int_int. A name such as _foo_int_int contains the function name, the number and type of function parameters, and C++ uses this mechanism to implement function overloading.

In order to realize the mixed programming of C and C++, C++ provides the C connection exchange designated symbol extern "C" to solve the problem of name matching. After adding extern "C" before the function declaration, the compiler will follow the C language method. The function is compiled to _foo, so that the C++ function can be called from the C language.

26. What is the size of the class in each case?

class A {};
int main(){
  cout<<sizeof(A)<<endl;// 输出 1;
  A a; 
  cout<<sizeof(a)<<endl;// 输出 1;
  return 0;
}

The size of an empty class is 1. In C++, an empty class occupies one byte, so that instances of objects can be distinguished from each other. Specifically, empty classes can also be instantiated, and each instance has a unique address in memory. Therefore, the compiler will implicitly add a byte to the empty class, so that after the empty class is instantiated, it will have Unique memory address. When the blank class is used as the base class, the size of the class is optimized to 0, and the size of the subclass is the size of the subclass itself. This is known as blank base class optimization.

The instance size of an empty class is the size of the class, so sizeof(a)=1 byte. If a is a pointer, sizeof(a) is the size of the pointer, which is 4 bytes.

class A { virtual void Fun(){} };
int main(){
  cout<<sizeof(A)<<endl;// 输出 4(32位机器)/8(64位机器);
  A a; 
  cout<<sizeof(a)<<endl;// 输出 4(32位机器)/8(64位机器);
  return 0;
}

Because there is a virtual function table pointer __vptr in the class object with virtual function, its size is 4 bytes

class A { static int a; };
int main(){
  cout<<sizeof(A)<<endl;// 输出 1;
  A a; 
  cout<<sizeof(a)<<endl;// 输出 1;
  return 0;
}

Static members are stored in the static storage area and do not occupy the size of the class, nor do ordinary functions occupy the size of the class

class A { int a; };
int main(){
  cout<<sizeof(A)<<endl;// 输出 4;
  A a; 
  cout<<sizeof(a)<<endl;// 输出 4;
  return 0;
}

class A { static int a; int b; };;
int main(){
  cout<<sizeof(A)<<endl;// 输出 4;
  A a; 
  cout<<sizeof(a)<<endl;// 输出 4;
  return 0;
}

The static member a does not occupy the size of the class, so the size of the class is the size of the b variable, which is 4 bytes.

27. What factors affect the size of class objects?

  1. The size of the non-static member variables of the class, static members do not occupy the space of the class, and member functions do not occupy the space of the class;

  2. Memory alignment The size of the space allocated in addition, the data in the class also needs to be memory aligned;

  3. If the virtual function is used, the vptr pointer will be inserted into the class object, plus the size of the pointer;

  4. When the class is a derived class of a certain class, the data members of the base class part inherited by the derived class will also exist in the space of the derived class, and the derived class will also be extended.

15. What happens to the stack when the this pointer calls the member variable?

When accessing a non-static member of a class in a non-static member function of a class, the compiler will automatically pass the address of the object to the function as an implicit parameter, which is the this pointer.

Even if you do not write this pointer, the compiler will add this when linking, and access to each member is through this.

For example, when you create multiple objects of a class, when you call a member function of the class, you don't know which object is calling. At this time, you can check which object is calling by checking the this pointer. This pointer is first pushed onto the stack, then the parameters of the member function are pushed onto the stack from right to left, and finally the function return address is pushed onto the stack.

28. Write the constructor, destructor and assignment function of the class String. The prototype of the known class String is:

class String
{
public:
    String(const char *str = NULL); // 普通构造函数
    String(const String &other); // 拷贝构造函数
    ~ String(void); // 析构函数
    String & operator =(const String &other); // 赋值函数
private:
    char *m_data; // 用于保存字符串
};
1 //普通构造函数
 2 String::String(const char *str)
 3 {
 4     if(str==NULL)
 5     {
 6         m_data = new char[1];   // 得分点:对空字符串自动申请存放结束标志'\0'的空
 7         *m_data = '\0';         //加分点:对m_data加NULL 判断
 8     }
 9     else
10     {
11         int length = strlen(str);
12         m_data = new char[length+1];    // 若能加 NULL 判断则更好
13         strcpy(m_data, str);
14     }
15 }
16 // String的析构函数
17 String::~String(void)
18 {
19     delete [] m_data;
20 }
21 //拷贝构造函数
22 String::String(const String &other) // 得分点:输入参数为const型
23 {
24     int length = strlen(other.m_data);
25     m_data = new char[length+1];    //加分点:对m_data加NULL 判断
26     strcpy(m_data, other.m_data);
27 }
28 //赋值函数
29 String & String::operator =(const String &other) // 得分点:输入参数为const型
30 {
31     if(this == &other)  //得分点:检查自赋值
32         return *this;
33     delete [] m_data;   //得分点:释放原有的内存资源
34     int length = strlen( other.m_data );
35     m_data = new char[length+1];    //加分点:对m_data加NULL 判断
36     strcpy( m_data, other.m_data );
37     return *this;   //得分点:返回本对象的引用
38 }

29. Please name as many roles of the static and const keywords as possible?

The static keyword has at least the following five functions:
(1) The scope of the static variable in the function body is the function body. Unlike the auto variable, the memory of the variable is only allocated once, so its value remains the same as the last time when it is called next time. (
2) Static global variables in a module can be accessed by functions used in the module, but cannot be accessed by other functions outside the module;
(3) Static functions in a module can only be called by other functions in this module. , the scope of use of this function is limited to the module in which it is declared;
(4) The static member variables in the class belong to the entire class, and there is only one copy for all objects of the class;
(5) The static member in the class The function is owned by the entire class. This function does not receive the this pointer, so it can only access the static member variables of the class.

The const keyword has at least the following five functions:
(1) To prevent a variable from being changed, the const keyword can be used. When defining the const variable, it is usually necessary to initialize it, because there is no chance to change it later;
(2) For pointers, the pointer itself can be specified as const, or the data pointed to by the pointer can be specified as const , or both are specified as const;
(3) In a function declaration, const can modify the formal parameter, indicating that it is an input parameter, and its value cannot be changed within the function;
(4) For a member function of a class, if specified If it is of const type, it means that it is a constant function and cannot modify the member variables of the class;
(5) For the member function of a class, sometimes the return value must be specified as a const type, so that its return value is not an "lvalue" ". E.g:

const classA operator*(const classA& a1,const classA& a2);
operator*的返回结果必须是一个const对象。如果不是,这样的变态代码也不会编译出错:  
classA a, b, c;  
(a * b) = c; // 对a*b的结果赋值  
操作(a * b) = c显然不符合编程者的初衷,也没有任何意义

30. Please write a C function, if the processor is Big_endian, it will return 0; if it is Little_endian, it will return 1.

int checkCPU()
{
    {
        union w
        {
            int a;
            char b;
        } c;
        c.a = 1;
        return (c.b == 1);
    }
}

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=324042168&siteId=291194637