• 【C++难点收录】“C++难?,你真的理解了这些吗?”《常见面试题》【二】


    虚继承

    概念:解决菱形继承的数据冗余和二义性

    原理:将虚基类对现象放到公共位置(vs是放到整个对象尾部),虚基表中存偏移量,来计算虚基类的位置;

    没加virtual之前

    动画18

    加了virtual只后的内存情况

    动画17

    image-20220830080912152

    虚继承中,将A通常叫做虚基类

    image-20220830081837765

    虚函数

    概念:虚函数重写是多态条件之一

    多态原理:虚函数地址放到对象的虚表(虚函数表)中,多态指向谁调用本质是运行到对象虚表找到要调用的虚函数

    析构函数可以是虚函数吗?什么场景下析构函数是虚函数?

    答:可以,并且最好把基类的析构函数定义成虚函数

    image-20220830075712354

    总结:虚函数虚基类两个地方都用到virtual关键字,它们之间没有一点关联,不要联系到一起。

    重写(覆盖)

    满足重写,必须接口一致,并且是虚函数继承,重写虚函数的继承是一种接口继承,什么是接口继承呢?

    以下程序输出结果是() :

    class A
    {
    public:
    	virtual void func(int val = 1){ std::cout<<"A->"<< val <func()
                           
        }
    };
    class B : public A
    {
    public:
    	void func(int val=0){ std::cout<<"B->"<< val <test();//p->test(p)
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    输出:B->1;重写,只会重写函数的实现,不对(int val=0)中的val=0干扰,可以是void func(int a)void fun(int)都会构成重写,所以val的值还是对象A的val

    总结:子类的缺省参数不起作用,重写虚函数是一种接口继承,也就可以理解成函数、返回值、参数(包括缺省参数)都是父类继承下来,所以这里用的 父类的缺省参数

    隐藏

    ( 1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无 virtual
    关键字,基类的函数将被隐藏(注意别与重载混淆)。
    ( 2)如果派生类的函数与基类的函数同名, 并且参数也相同, 但是基类函数没有 virtual
    关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。
    示例程序中:

    #include 
    class Base
    {
    public:
    virtual void f(float x){ cout << "Base::f(float) " << x << endl; }
    		void g(float x){ cout << "Base::g(float) " << x << endl; }
    		void h(float x){ cout << "Base::h(float) " << x << endl; }
    };
    class Derived : public Base
    {
    public:
    virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }
    		void g(int x){ cout << "Derived::g(int) " << x << endl; }
    		void h(float x){ cout << "Derived::h(float) " << x << endl; }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    ( 1)函数 Derived::f(float)覆盖了 Base::f(float)。
    ( 2)函数 Derived::g(int)隐藏了 Base::g(float),而不是重载。
    ( 3)函数 Derived::h(float)隐藏了 Base::h(float),而不是覆盖。

    多态

    1、虚函数的重写 2、父类的指针或引用调用才符合多态条件

    多态是在运行时到指向对象的虚表中查找要调用的虚函数的地址来进行调用,如果没加*或&,就会在编译时直接确认类型调用函数的地址

    纯虚函数

    //virtual void fun(){}//虚函数
    	virtual void fun() = 0;//纯虚函数
    
    • 1
    • 2

    包含纯虚函数的类叫抽象类,抽象类不能实例化出对象

    image-20220829200400785

    纯虚函数的作用:

    1、强制子类去完成重写:父类的纯虚函数virtual void fun() = 0;子类重写:virtual void func(){}

    2、表示抽象的类型,抽象就是在现实中没有对应的实体的。

    虚函数表

    image-20220829173844321

    在32位平台下,没有加virtual大小为1,加了之后就会变4,这是因为加了虚函数关键字,底层会有个vftptr(vitual function table pointer)虚函数表指针

    1、虚函数存在哪?

    答:代码段

    2、虚函数表(虚表)存在哪?

    代码段(常量区)

    image-20220829203205038

    set

    map

    下面两种方式等同

    //mp.insert(pair(6, 6));
    	mp.insert(make_pair(5, 5));
    
    • 1
    • 2

    日常大家喜欢用make_pair因为它不用声明模板参数,自动推

    image-20220831193822769

    #include
    using namespace std;
    #include
    #include
    
    int main()
    {
    	mapmp;
    	mp.insert(pair(1, 1));
    	mp.insert(pair(3, 3));
    	mp.insert(pair(6, 6));
    	mp.insert(make_pair(5, 5));
    	auto lt = mp.begin();
    	while (lt != mp.end())
    	{
    		cout << lt->first << ":" << lt->second << endl;
    		//cout << (*lt).first << ":" << (*lt).second << endl;
    		lt++;
    	}
    	cout << endl;
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    image-20220831194236883

    总结:

    map

    1、增 insert+operator[]

    2、删 erase

    3、查 find+(不建议operator[])

    4、改 operator[]

    5、遍历 iterator+范围for -》遍历出来的数据是按k排序的,应为底层是搜索数,走的是

    要注意的是map中存的是pair键值对

    面试题

    C++的缺陷有哪些?

    多继承就是一个问题-》菱形继承-?虚继承-》底层结构的对象模型非常复杂,且有一定效率损失

    什么是菱形继承?菱形继承问题是什么?-》代码冗余,会有二义性-》如何解决?-》虚继承-》解决原理是什么?

  • 相关阅读:
    Kafka是什么,以及如何使用SpringBoot对接Kafka
    PostgreSQL basebackup备份和恢复
    灾难恢复架构规划要点
    react useContext 用法
    CocoaPods公有库和私有库制作
    Python武器库开发-基础篇(三)
    【已解决】将一个2708行64列的在GPU上的张量z0矩阵保存下来,格式为csv
    汽车IVI中控开发入门及进阶(二十五):CVBS视频流
    IIC总线概述和通信时序代码详细图文解析
    110道 MySQL面试题及答案 (持续更新)
  • 原文地址:https://blog.csdn.net/weixin_51568389/article/details/126677362