📜  有关虚拟函数和抽象类的C++面试问题(1)

📅  最后修改于: 2023-12-03 15:40:17.658000             🧑  作者: Mango

有关虚拟函数和抽象类的C++面试问题

在C++中,虚拟函数和抽象类是两个重要的概念。在面试中,经常会涉及到这两个概念。下面将介绍一些常见的面试问题,并提供相应的回答。

虚拟函数是什么?

虚拟函数是在基类中声明的函数,并且在派生类中进行重写的函数。它可以通过指向基类对象的指针或引用访问派生类中的特定函数。

在C++中,虚拟函数可以用关键字 virtual 来声明。例如:

virtual void foo();

注意:虚拟函数必须在公共接口中声明,否则无法从派生类中调用。

什么是纯虚拟函数?

纯虚拟函数是一个没有实现的虚拟函数。它可以通过在函数声明中加上 "= 0" 来确保它是纯虚拟函数。例如:

virtual void foo() = 0;

注意:纯虚拟函数不能在基类中实现,而是必须在派生类中实现。

什么是抽象类?

抽象类是一个包含至少一个纯虚拟函数的类。抽象类不能被实例化,而必须通过基于该类的派生类来实例化。

抽象类通常作为一个抽象的概念存在,只提供一些接口,并且需要派生类来实现这些接口。

为什么需要抽象类?

抽象类可以提供一个框架,只需要提供一些接口和抽象方法。这样可以使得代码更加通用和可扩展。

抽象类的一个重要用途是通过这种方式来实现多态性。许多派生类可以从同一个抽象类派生,并实现相同的接口,并且可以通过指向该抽象类对象的指针来访问不同的实现。

虚拟函数和普通函数有什么区别?

虚拟函数是指在基类中声明的函数,而可以在派生类中进行重写。而普通函数则是在类中定义的普通函数。

虚拟函数的主要特点是:在运行时,可以根据对象的实际类型来调用正确版本的函数。因此,虚拟函数可以实现多态性。

什么时候需要虚拟析构函数?

在使用指向派生类的基类指针或引用时,需要使用虚拟析构函数。如果析构函数不是虚拟函数,就会出现问题。这是因为按照基类对象的类型进行销毁时,只有基类的析构函数被调用。

因此,如果有一个基类指针或引用,指向的是派生类的实例,而这个基类指针或引用必须在结束时,用delete删除这个实例,那么这个基类必须有虚拟析构函数。

怎么通过派生类调用基类中的函数?

在派生类中,可以通过以下两种方式来调用基类中的函数:

  • 使用作用域解析运算符(::)调用基类的函数。
class Base
{
public:
    void foo() { cout << "Base::foo()" << endl; }
};

class Derived : public Base
{
public:
    void bar() { Base::foo(); }      // 调用基类的函数
};
  • 使用父类指针或引用来调用基类的函数。
Base* pBase = new Derived();
pBase->foo();       // 调用基类的函数
怎么禁止派生类重写虚拟函数?

可以使用关键字 final 来标记虚拟函数,防止在派生类中被重写。例如:

class Base
{
public:
    virtual void foo() final;
};

class Derived : public Base
{
public:
    // 无法重写Base中的foo函数
};
怎么禁止基类实例化?

可以通过将构造函数声明为 protected 来禁止基类的实例化。这样,只有派生类才能调用构造函数来创建类的实例。

class Base
{
protected:
    Base() {}
};

class Derived : public Base
{
public:
    Derived() {}
};
怎么判断一个类是否为抽象类?

只要类中有至少一个纯虚拟函数,这个类就是一个抽象类。

class Shape
{
public:
    virtual void draw() = 0;
};
怎么使用抽象类?

抽象类通常是通过基类派生出一系列的派生类来使用。这些派生类必须实现抽象类中所声明的所有纯虚拟函数,否则它们也将成为抽象类。

例如:

class Circle : public Shape
{
public:
    void draw() { /* 实现圆形的绘制 */ }
};

class Rectangle : public Shape
{
public:
    void draw() { /* 实现矩形的绘制 */ }
};

这些派生类可以通过基类的指针或引用进行访问,也支持使用多态性来访问不同的实现。例如:

Shape* pShape = new Circle();
pShape->draw();     // 调用Circle::draw()

pShape = new Rectangle();
pShape->draw();     // 调用Rectangle::draw()
怎么判断一个类是否继承自某个基类?

可以使用 is_base_of 模板来判断一个类是否继承自某个基类。例如:

#include <type_traits>

class Base {};

class Derived : public Base {};

bool isDerivedFromBase = std::is_base_of<Base, Derived>::value;    // true
总结

本文介绍了一些关于C++中虚拟函数和抽象类的常见面试问题,涉及虚拟函数、纯虚拟函数、抽象类、基类与派生类之间的关系、多态性等内容。希望对读者有所帮助。