继承和多态常见的面试问题(二)

777 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第16天,点击查看活动详情

  1. 面向对象设计中的继承和组合,下面说法错误的是 ( )

    A. 继承允许我们覆盖重写父类的实现细节,父类的实现对于子类是可见的,是一种静态复用,也称为白盒复用

    B. 组合的对象不需要关心各自的实现细节,之间的关系是在运行时候才确定的,是一种动态复用,也称为黑盒复用

    C. 优先使用继承,而不是组合,是面向对象设计的第二原则

    D. 继承可以使子类能自动继承父类的接口,但在设计模式中认为这是一种破坏了父类的封装性的表现

    📝 C,优先使用组合,而不是继承。

  2. 以下关于纯虚函数的说法,正确的是 ( )

    A. 声明纯虚函数的类不能实例化对象

    B. 声明纯虚函数的类是虚基类

    C. 子类必须实现基类的纯虚函数

    D. 纯虚函数必须是空函数

    📝 A,但是声明纯虚函数的类可以定义指针。这里选最正确的。

  3. 关于虚函数的描述正确的是 ( )

    A. 派生类的虚函数与基类的虚函数具有不同的参数个数和类型

    B. 内联函数不能是虚函数

    C. 派生类必须重新定义基类的虚函数

    D. 虚函数可以是一个 static 型的函数

    📝 B,首先排除 AC,其次虚函数的地址是放在对象的虚表中,如果要形成多态,就必需要用对象的指针或引用来调用,而 static 就意味着是静态的,你都没有 this 指针,那就不合理了。内联函数不能是虚函数其实是一个存疑的选项,己验证,在 VS2017 下,内联函数加上虚函数后依然能编译通过,但是你要知道内联函数对编译器而言只是建议,实际上一个函数真的成为内联函数,它就不可能是虚函数,因为内联函数是没有地址的,它直接在调用的地方展开,而虚函数是要把地址放到虚函数表中,所以这里一定会把 inline 忽略掉。

  4. 对象访问普通函数快还是虚函数更快 ?

    答:普通函数快,因为虚函数要构成多态,运行时调用虚函数需要到虚函数表中去查找。可以去看看调用普通函数和虚函数的汇编代码,调用虚函数明显要比调用普通函数要多几步。

  5. 虚函数表是在什么阶段生成的,存在哪的 ?

    答:虚函数表是在编译阶段就生成的,一般情况下存在代码段 (常量区)的。

  6. 多继承中指针偏移问题?下面说法正确的是 ( )

class Base1 { public: int _b1; };
class Base2 { public: int _b2; };
class Derive : public Base1, public Base2 { public: int _d; };
int main(){
 	Derive d;
 	Base1* p1 = &d;
 	Base2* p2 = &d;
 	Derive* p3 = &d;
 	return 0; 
}

A. p1 == p2 == p3

B. p1 < p2 < p3

C. p1 == p3 != p2

D. p1 != p2 != p3

📝 如下图,所以选择 C 选项。注意 p1 和 p3 虽然都指向同一地址,但是它们的类型不一样,p1 是 Base1 的大小,p3 是 Derive 的大小。

在这里插入图片描述