【C++】C++最重要的面试知识点汇总及详细解释

一、设计模式

1、单例模式

(1)单例模式关键点

关键点有四个:
(1)构造函数必须是私有的
(2)声明静态单例对象
(3)构造单例之前要加锁
(4)需要两次检查单例实例是否为空,分别在锁之前和锁之后

(2)单例模式实现代码

代码:

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)可能的问题:

1.为何要检测2次?
有可能延迟或者缓存原因,造成构造多个实例,违反了单例的初衷。
2.构造函数能否公有化
不,单例类的构造函数必须私有化,单例类不能被实例化,只能被静态调用。
3.lock住的对象为什么要是object对象,可以是int型吗?
不行,锁住的必须是个引用类型,如果锁值类型,每个不同的线程在声明的时候值类型变量的地址都不一样,那么上个线程锁住的东西,下个线程进来会认为根本没有锁,相当于每次都锁了不同的门。而引用类型的变量地址是相同的,每个线程进来判断锁都是判断同一个地址,相当于锁在同一扇门,起到了锁的作用。

2、观察者模式

二、继承

(1)三种继承方式

三种继承方式,public,protected和private。
public继承:父类成员在子类中保持原有的访问级别
private继承:父类成员在子类中变成private成员
protected继承:父类中的public会变成protected,private还是private,protected还是protected。
private成员在子类中依然存在,但是却无法访问到。不论种方式继承基类,派生类都不能直接使用基类的私有成员。

(2)三种设置的区别

需要被外界访问的成员设置为public,只能在当前类中访问的成员设置为private,只能在当前类和子类中访问的成员设置为protected。

三、多态

(1)多态的种类和定义

多态就是多种形态,C++的多态分为静态多态与动态多态。
静态多态就是重载,因为在编译期决议确定,所以称为静态多态。在编译时就可以确定函数地址。
动态多态就是通过继承重写基类的虚函数实现的多态,因为实在运行时决议确定,所以称为动态多态。运行时在虚函数表中寻找调用函数的地址。

(2)多态成立的条件

动态多态,也就是我们通常问的多态,成立的3个条件:
(父类的同名函数中加virtual,子类的同名函数可以加也可以不加)
a. 要有继承:
b. 要有虚函数重写;
c. 父类指针(引用)指向子类对象
多态其实就是一个接口,多种方法。

(3)多态实现代码

分析一下下面这个代码的执行结果,注释我写在代码中了。

#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;
} 

代码的执行结果为:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_38391210/article/details/108183203