C++面试常问

本文探讨了C++中虚拟函数的优缺点,包括内存开销、效率影响和封装安全。接着讨论了多继承的利弊,特别是菱形继承与虚继承的影响。还解释了为何需要虚析构函数,以及C++中为何没有虚拟构造函数。文章深入浅出地分析了哪些函数不能是虚函数,如静态、构造和友元函数。此外,概述了类的内存布局,包括虚函数、多继承和虚继承的情况。最后,文章涵盖了动态类型转换(dynamic_cast)的工作原理,内存模型,内存对齐的重要性,以及std::shared_ptr的实现、placement new的意义和allocator的使用和意义。
摘要由CSDN通过智能技术生成

问:virtual function的优缺点

优点:实现多态
缺点:MFC中的消息机制以及Qt中都没有采用C++中的虚函数机制,原因大概如下~

1.在子类很少覆盖基类函数实现的时候内存开销太大,每个类需要产生一张虚表,每生成一个对象的时候,需要在对象里存放一个vptr。

2.基类指针指向派生类对象的情况下,不方便内联优化(有些情况可以内联,参考我前面的文章

3.在执行效率上肯定多了一些开销,需要寻找函数地址

4.虚表的存在可能破坏一些封装安全,可以通过vptr绕过private的限制

问:多继承的优缺点

好处:简单来讲就是为了实现多个基类特有的功能

缺点:菱形继承;二义性(可通过虚继承解决)

以下代码出现菱形继承


class A
{
public:
    int _a;
};
class B:public A
{
public:
    int _b;
};
class C:public A
{
public:
    int _c;
};
class D:public B,public C
{
public:
    int _d;
};
 
int main()
{
    D d;
    d._a = 10;//这里调用成员的时候就会出现错误,对_a的访问不明确
 
    d._b = 2;
    d._c = 3;
    d._d = 4;
    return 0;
}

以下代码可解决报错,但依旧冗余


d.B::_a = 10;
d.C::_a = 20;

使用虚继承解决

class B:virtual public A
class C:virtual public A

总结:
1.虚继承解决了在菱形继承中子类对象包含多分父类对象的数据冗余和浪费空间的问题
2.虚继承体系看起来很复杂,在实际应用中我们通常不会定义如此复杂的集成体系。一般不到万不得已不要使用菱形虚拟继承,因为它解决数据冗余问题的同时也带来了性能上的损耗

问:为什么要用virtual destructor?

为了能正常调用子类的析构函数,否则会出现只调用基类析构函数而没有调用子类析构函数情况。(如果子类有指针成员且申请了堆空间,不调用子类调用析构函数就会造成内存泄漏)

class Base
{
public:
    virtual ~Base()
    {         
         cout<<"delete Base"<<endl;
    };
};

class Derive : public Base
{
  public:
    int* p;
    Derive()
    {
      p = new int;//构造时申请空间
    }
   ~Derive()
   {
       delete p;//析构时释放空间
       cout<<"delete Derive"<<endl;
   };
};

int main()
{
    Base *pbase = new Derive;
    delete pbase ;
    //如果析构函数不是virtual,就只会调用当前指针类型的析构函数(也就是基类Base的析构函数)。
    //反之,则会根据虚表找到派生类的析构函数并调用。
    //由于C++语言机制(或者说编译器会插入一些额外的代码),调用完子类的析构函数后会自动调用基类的析构函数

    return 0;
}

问:为什么没有virtual constructor?

第一点,构造函数执行前,对象的内存信息都没有,vptr也没有初始化,如何找到虚函数表,实现虚调用。其次,需要理解虚函数的意义,他是为了实现多态,让子类去覆盖父类的操作,但是前提是你需要知道当前的类型是什么,而C++里面构造函数可以说决定了他的类型。另外,构造函数与析构函数的执行不同,他是从父类开始一步一步的构造成一个子类(即使父类没有构造函数也可能会被编译器合成一个),所以你不能跳过父类的构造函数,子类的很多成员可能需要在父类的基础上去初始化。
不过,从设计的角度来考虑的话,虚构造的思想还是有意义的,和我们设计模式中的工厂模式有点类似,根据不同的类型去做不同的初始化。Delphi语言因为有一个祖先基类,所以可以做到虚构造,而C++从语言层面来讲不存在真正意义上的虚构造函数。

问:哪些函数不能是虚函数?

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值