C/C++ 常见1000道面试题( 26 )

C/C++ 常见1000道面试题( 26 )
最新回答
风行水上

2026-07-15 06:14:56

98. 类什么时候会析构?
  • 对象生命周期结束,被销毁时:当对象离开其作用域(如局部对象在函数结束时)或被显式销毁(如全局对象在程序结束时),其析构函数会被调用。
  • delete指向对象的指针时,或delete指向对象的基类类型指针,而其基类析构函数是虚函数时:

    直接使用delete操作符释放动态分配的对象时,会调用该对象的析构函数。

    若通过基类指针删除派生类对象,且基类析构函数为虚函数,则能确保调用派生类的析构函数,避免资源泄漏。

  • 对象i是对象o的成员,o的析构函数被调用时,对象i的析构函数也被调用:复合对象的析构会按成员变量的声明顺序逆序调用其析构函数。
99. 为什么友元函数必须在类内部声明?
  • 编译器需读取声明以理解数据类型规则:友元函数需访问类的私有成员,编译器需通过类内部的声明确认其权限。
  • 明确访问控制关系:类内部声明友元函数可清晰定义“谁可访问私有部分”,避免外部随意声明导致的封装破坏。
100. 介绍一下C++里面的多态?
  • 静态多态(编译时多态):

    重载:同一作用域内同名函数通过参数列表区分,编译时确定调用版本。

    模板:编译器根据模板实例化生成特定代码,如template<typename T> void func(T a) {}。

  • 动态多态(运行时多态):

    虚函数与覆盖:通过虚函数表(vtable)和虚函数指针(vptr)实现。基类指针指向派生类对象时,调用派生类覆盖的虚函数。

    纯虚函数:声明为virtual int fun() = 0;的虚函数,强制派生类实现,用于抽象基类。

    动态绑定:函数调用版本由实参类型在运行时决定,如基类指针调用派生类方法。

101. 用C语言实现C++的继承
  • 结构体嵌套模拟继承:通过将基类结构体作为派生类结构体的成员,实现属性继承。
  • 函数指针模拟方法:在结构体中定义函数指针,指向不同实现,模拟虚函数。
  • 示例代码:
// 基类typedef struct { void (*print)(void*);} Base;void base_print(void* self) { printf("Base printn");}// 派生类typedef struct { Base base; // 继承Base的成员 void (*derived_print)(void*); // 新增方法} Derived;void derived_print(void* self) { printf("Derived printn");}int main() { Derived d = {{base_print}, derived_print}; d.base.print(&d); // 调用基类方法 d.derived_print(&d); // 调用派生类方法 return 0;}102. 继承机制中对象之间如何转换?指针和引用之间如何转换?
  • 向上类型转换(Upcasting):

    安全自动转换:派生类指针/引用转为基类指针/引用,如Derived* d; Base* b = d;。

  • 向下类型转换(Downcasting):

    需动态类型识别(RTTI):基类指针/引用转为派生类指针/引用需显式使用dynamic_cast,如Base* b; Derived* d = dynamic_cast<Derived*>(b);。

    失败处理:若转换失败,dynamic_cast返回nullptr(指针)或抛出异常(引用)。

103. 组合与继承优缺点?
  • 继承:

    优点:表达“is-a”关系,支持方法重写以扩展功能。

    缺点:

    父类内部细节对子类可见,破坏封装。

    编译时确定方法行为,无法运行时动态修改。

    父类修改需同步调整子类,耦合度高。

  • 组合:

    优点:

    隐藏内部细节,仅通过接口访问成员对象。

    低耦合,修改成员类不影响当前类。

    支持运行时动态绑定成员对象(如通过set方法替换)。

    缺点:

    需管理更多对象,可能增加复杂度。

    需精心设计接口以协调多个成员对象。

104. 左值右值
  • 左值:

    可取地址、有名字的值,如变量int a = 10;中的a。

    可出现在赋值语句左侧(如a = 20;)。

  • 右值:

    纯右值(prvalue):临时对象或字面量,如b + c、42。

    将亡值(xvalue):即将被移动的对象,如std::move(a)的返回值。

    不可取地址,通常作为临时值使用。

  • 引用类型:

    左值引用:绑定到左值,如int& ref = a;。

    右值引用:绑定到右值,如int&& rref = b + c;,用于移动语义和完美转发。

    常量左值引用:可绑定到右值(如const int& ref = 42;),但仅限只读访问。

  • std::move:将左值强制转换为右值,启用移动语义,避免不必要的拷贝。