[C++] Summary and detailed explanation of the most important interview knowledge points of C++

One, design pattern

1. Singleton mode

(1) Key points of singleton mode

There are four key points:
(1) The constructor must be private
(2) The static singleton object is declared
(3) The singleton must be locked before the singleton is constructed
(4) It is necessary to check whether the singleton instance is empty twice, each in the lock Before and after lock

(2) Singleton mode implementation code

Code:

class Singleton{
    
    
	private:
		Singleton();
		static Singleton *m_singleton=NULL;
		static object obj=new object();
	public:
		Singleton & getSingleton()
		{
    
    
			if(m_singleton==NULL)
			{
    
    
				lock(obj);
				{
    
    
					if(m_singleton==NULL)
					m_singleton=new Singleton();
				}
			}
			return m_singleton;
		}
};
}

(3) Possible problems:

1. Why do we need to test twice?
It may be delayed or cached, causing multiple instances to be constructed, which violates the original intention of the singleton.
2. Can the constructor be publicized?
No, the constructor of the singleton class must be privatized. The singleton class cannot be instantiated and can only be called statically.
3. Why should the locked object be an object, can it be an int type?
No, the lock must be a reference type. If the value type is locked, the address of the value type variable is different when each different thread is declared, then the thing locked by the previous thread, the next thread will think that there is no Locking is equivalent to locking a different door each time. The variable address of the reference type is the same, and each thread comes in to judge the lock to judge the same address, which is equivalent to being locked on the same door and acting as a lock.

2. Observer mode

Second, inheritance

(1) Three ways of inheritance

Three inheritance methods, public, protected and private.
Public inheritance: members of the parent class maintain the original access level in the child class.
Private inheritance: members of the parent class become private members in the child class.
Protected inheritance: public in the parent class becomes protected, private or private, protected or protected .
Private members still exist in the subclass, but they cannot be accessed. Regardless of how the base class is inherited, derived classes cannot directly use the private members of the base class.

(2) The difference between the three settings

The members that need to be accessed by the outside world are set to public, the members that can only be accessed in the current class are set to private, and the members that can only be accessed in the current class and subclasses are set to protected.

Three, polymorphism

(1) Types and definitions of polymorphism

Polymorphism is a variety of forms, C++ polymorphism is divided into static polymorphism and dynamic polymorphism.
Static polymorphism is overloading, because it is determined at compile time, so it is called static polymorphism. The function address can be determined at compile time.
Dynamic polymorphism is the polymorphism achieved by inheriting and rewriting the virtual function of the base class. Because the resolution is determined at runtime, it is called dynamic polymorphism. Look for the address of the calling function in the virtual function table at runtime.

(2) Conditions for the establishment of polymorphism

Dynamic polymorphism, that is, the polymorphism we usually ask, three conditions are established:
(add virtual to the function of the same name of the parent class, and the function of the same name of the subclass can be added or not)
a. There must be inheritance:
b. Yes There are virtual function overrides;
c. The parent class pointer (reference) points to the child class object.
Polymorphism is actually an interface with multiple methods.

(3) Polymorphic implementation code

Analyze the execution result of the following code, and the comment I wrote in the code.

#include <iostream>
#include <stdlib.h>
using namespace std;
 
class CA
{
    
    
public:
    void f()
    {
    
    
        cout << "CA f()" << endl;
    }
    virtual void ff()
    {
    
    
        cout << "CA ff()" << endl;
        f();
    }
};
 
class CB : public CA
{
    
    
public :
    virtual void f()
    {
    
    
        cout << "CB f()" << endl;
    }
    void ff()
    {
    
    
        cout << "CB ff()" << endl;
        f();
        CA::ff();
    }
};
class CC : public CB
{
    
    
public:
    virtual void f()
    {
    
    
        cout << "C f()" << endl;
    }
};
 
int main()
{
    
    
    CB b;
    CA *ap = &b;//父类指针指向子类,第一种多态的方式
    CC c;
    CB &br = c;//引用,第二种多态的方式
    CB *bp = &c;//父类指针指向子类,第一种多态的方式
 
    ap->f();//输出为CA f(),因为CA这个类中的f函数前面没有virtual,所以不是虚函数,不存在多态,那么此时调用的就是CA中的f()。
    cout << endl;
 
    b.f();//输出为CB f(),这里的b不存在多态,因为没有满足多态的第二个条件:父类指针(引用)指向子类对象。所以调用的就是CB中的f()。
    cout << endl;
 
    br.f();//输出为C f(),因为CB中的f()前面有virtual,是虚函数,而且将父类CB指针指向了子类CC,所以调用的就是CC中的f()。
    cout << endl;
 
    bp->f();//输出为C f(),这里的bp->f()和br.f()的输出结果是相同的,因为bp是父类CB指针指向子类CC,br是引用。而且CB中的f()是虚函数,满足多态的三个条件,实现了多态,所以调用CC中的f()。
    cout << endl;
 
    ap->ff();//输出为CB ff() CB f() CA ff() CA f()。CA中的ff()是虚函数,实现了多态,所以调用的是CB中的ff(),先输出CB ff();再调用f(),因为CA中的f()不是虚函数,没有实现多态,所以是直接调用CA中的f(),输出CA f();再执行CA::ff()这一句,调用CA中的ff(),先输出CA ff(),再执行f()函数,因为不存在多态,直接调用CA中的f(),输出CA f()。
    cout << endl;
 
    bp->ff();//输出CB ff() C f() CA ff() CA f()。CB中的ff()前面没有virtual,不是虚函数,所以直接调用CB中的ff(),先输出CB ff();再执行f()这一句,因为f()在CB中是虚函数,所以调用CC中的f()函数,输出C f();最后执行CA::ff()这一句,需要调用CA中的ff()函数,先输出CA ff(),再调用f(),由于f()在CA中不是虚函数,所以直接调用CA中的f(),输出CA f()。
    cout << endl;
 
    return 0;
} 

The execution result of the code is:
Insert picture description here

Guess you like

Origin blog.csdn.net/qq_38391210/article/details/108183203