📅  最后修改于: 2023-12-03 14:59:51.756000             🧑  作者: Mango
在 C++ 中,虚函数和抽象类都是面向对象编程中的重要概念。以下是一些常见的关于虚函数和抽象类的面试题。
虚函数是用来支持多态性的特殊函数。虚函数可在派生类中重载,使得派生类的对象能够被当作基类对象使用。通常情况下,我们只需要在基类中声明虚函数,而不需要在基类中给出其实现。
在 C++ 中,将一个函数声明为虚函数只需要在函数声明前加上关键字 virtual
即可。例如:
class Shape {
public:
virtual void draw() {}
};
这里,Shape 类中的 draw
函数被声明为虚函数。
纯虚函数是一种特殊的虚函数,它没有默认的实现,必须在派生类中实现。我们可以通过在虚函数声明后面加上 = 0
来声明一个纯虚函数。例如:
class Shape {
public:
virtual void draw() = 0;
};
这里,Shape 类中的 draw
函数被声明为纯虚函数,没有默认实现。
抽象类是含有纯虚函数的类,它不能实例化,只能被用作派生类的基类。因为含有纯虚函数,抽象类也被称为接口类。
例如,以下是一个抽象类的示例:
class Shape {
public:
virtual void draw() = 0;
};
这里,Shape 类是一个抽象类,不能实例化,只能被用作派生类的基类。
派生类可以通过重载基类中的虚函数来实现自己的版本。例如:
class Circle : public Shape {
public:
virtual void draw() { /* 实现圆形的绘制 */ }
};
这里,Circle 类从 Shape 类派生,重载了 draw
函数,实现了圆形的绘制。
虚析构函数是在基类中声明为虚函数的析构函数。它的作用是确保基类指针正确地释放派生类对象。
例如:
class Shape {
public:
virtual ~Shape() {}
};
class Circle : public Shape {
public:
~Circle() {}
};
这里,Shape 类中的析构函数被声明为虚析构函数。Circle 类从 Shape 类派生,并重载了析构函数,但并没有声明为虚析构函数。
虚函数表是一张函数指针表,用于存储虚函数的地址。每个含有至少一个虚函数的类都有自己的虚函数表,其中存储着该类及其基类所有的虚函数地址。通过指向对象的指针或引用,程序可以在运行时查找虚函数表,并根据表中的地址调用相应的虚函数。
虚函数和普通函数的区别在于它们的调用方式不同。普通函数的调用是静态绑定的,即在编译期就已经确定调用哪个函数。而虚函数的调用是动态绑定的,即在运行时根据对象的实际类型确定调用哪个虚函数。这就是 C++ 中的多态性。
在多重继承中,如果有两个或多个基类有同名的虚函数,派生类必须重载该虚函数,并明确指定要调用哪个基类的虚函数。
例如:
class A {
public:
virtual void func() {}
};
class B {
public:
virtual void func() {}
};
class C : public A, public B {
public:
virtual void func() {
A::func(); // 调用 A 类的 func 函数
}
};
这里,C 类从 A、B 两个类中派生,并重载了 func
函数。在 func
函数中,可以通过作用域限定符 ::
告诉编译器要调用哪个基类的虚函数。
虚函数可以是私有的,但这样做的意义不大,因为私有虚函数无法被派生类重载。
例如:
class Shape {
private:
virtual void draw() {}
};
class Circle : public Shape {
public:
// 无法重载 Shape 类中被声明为私有的虚函数 draw
};
构造函数可以是虚函数,但析构函数必须是虚函数。
构造函数可以是虚函数的意义在于,如果一个类从另一个类派生并且需要在构造函数中执行其父类的构造函数,那么父类的构造函数需要声明为虚函数。
例如:
class Shape {
public:
virtual void draw() {}
Shape() {}
virtual ~Shape() {}
};
class Circle : public Shape {
public:
Circle() : Shape() {} // 调用 Shape 类的构造函数
~Circle() {}
};
这里,Shape 类中的构造函数和析构函数都被声明为虚函数,以便在派生类 Circle 中调用。
虚函数和抽象类是 C++ 面向对象编程中非常重要的概念。在面试中,往往需要掌握这些知识点,因此我们需要了解虚函数、纯虚函数、抽象类和虚析构函数的基本概念和用法,以及多重继承、虚函数表和派生类中的私有虚函数等常见问题。