C++ 面试题
- 构造函数不能声明为虚函数
- 虚函数表是如何在C++中被初始化的?
- 虚函数表和虚函数指针在内存中的具体存储方式是什么?
- 虚函数表和虚函数指针在内存中的存储方式对性能有何影响?
构造函数不能声明为虚函数
在C++中,构造函数不能声明为虚函数。这是因为在执行类的构造函数时,内存中还没有虚表,也就是还没有定义虚指针。因此,构造函数必须始终是非虚的。这是C++语言设计的一部分,以确保在对象构造期间能够正确地初始化虚函数表和虚指针。因此,构造函数不能声明为虚函数。
但是,C++中可以有虚析构函数。以下是一个示例代码:
#include<iostream>
using namespace std;
class Base {
public:
Base() {
cout << "Constructing base \n";
}
virtual ~Base() {
cout << "Destructing base \n";
}
};
class Derived : public Base {
public:
Derived() {
cout << "Constructing derived \n";
}
~Derived() {
cout << "Destructing derived \n";
}
};
int main(void) {
Derived *derived = new Derived();
Base *bptr = derived;
delete bptr;
return 0;
}
输出结果为:
Constructing base
Constructing derived
Destructing derived
Destructing base
这个例子展示了虚析构函数的用法。
虚函数表是如何在C++中被初始化的?
在C++中,虚函数表(vtable)是在对象的构造期间被初始化的。虚函数表是一个存储类的虚函数指针的数组,用于实现多态性。在对象构造期间,虚函数表会被填充为指向正确的虚函数的指针。
具体来说,虚函数表是在执行类的构造函数期间被初始化的。在构造函数执行期间,会为对象分配内存并初始化虚函数表。这确保了在对象构造期间能够正确地设置虚函数表和虚指针,以便在运行时进行正确的多态调用。
以下是一个示例代码,展示了虚函数表是如何在C++中被初始化的:
#include <iostream>
using namespace std;
class Base {
public:
virtual void func() {
cout << "Base::func()" << endl;
}
};
class Derived : public Base {
public:
void func() override {
cout << "Derived::func()" << endl;
}
};
int main() {
Base* basePtr = new Derived();
basePtr->func(); // 输出 "Derived::func()"
delete basePtr;
return 0;
}
在这个示例中,Base 类和 Derived 类都有一个虚函数 func。在 main 函数中,我们创建了一个 Derived 类的对象,并将其赋值给 Base 类的指针。当调用 basePtr->func() 时,会根据虚函数表中的指针调用 Derived::func(),实现了多态性。
虚函数表和虚函数指针在内存中的具体存储方式是什么?
- 虚函数表(vtable)和虚函数指针在内存中的具体存储方式是这样的:虚函数表是一个指针数组,存储了该类的虚函数的地址。
- 每个类有一个虚函数表,其中存储了该类的虚函数的地址。
- 而虚函数指针是一个指向虚函数表的指针,它存储了虚函数表的地址。
- 当调用一个虚函数时,实际上是通过虚函数指针找到对应的虚函数表,再从虚函数表中找到对应的虚函数地址进行调用。
这样的设计实现了多态性,使得在运行时能够正确地调用对象的实际类型的虚函数。
虚函数表和虚函数指针在内存中的存储方式对性能有何影响?
虚函数表和虚函数指针在内存中的存储方式会对性能产生一定影响。在C++中,虚函数表和虚函数指针是实现多态性的关键。它们的存储方式会影响程序的运行效率和内存占用。
具体影响包括:
-
内存占用:虚函数表和虚函数指针会占用额外的内存空间,每个对象都需要存储虚函数指针,而每个类都需要存储虚函数表。这会增加程序的内存占用。
-
性能开销:虚函数调用需要通过虚函数指针和虚函数表进行间接访问,这会引入额外的性能开销。相比于非虚函数调用,虚函数调用可能会更耗时。
-
缓存效率:虚函数表和虚函数指针的存储方式可能会影响CPU缓存的效率。由于虚函数表和虚函数指针存储在内存中,对于大型的类层次结构,可能会导致缓存未命中,从而影响程序的性能。
总的来说,虚函数表和虚函数指针的存储方式会对程序的性能产生一定的影响,特别是在对性能要求较高的场景下,需要谨慎设计类的继承结构和虚函数的使用。