面试题答案
一键面试1. 构造函数与多态性
- 构造函数不能是虚函数:
- 在 C++ 中,构造函数不能声明为虚函数。原因在于,虚函数的调用依赖于虚函数表指针(vptr),而这个指针是在对象构造过程中被初始化的。在构造函数执行时,对象还未完全构建好,虚函数表指针尚未正确初始化,所以无法实现基于虚函数表的多态调用。
- 例如:
class Base {
public:
// 这里尝试将构造函数声明为虚函数是错误的,会导致编译错误
// virtual Base() {}
Base() {
std::cout << "Base constructor" << std::endl;
}
};
class Derived : public Base {
public:
Derived() {
std::cout << "Derived constructor" << std::endl;
}
};
- 构造函数调用顺序与多态无关:
- 在创建派生类对象时,首先调用基类构造函数,然后调用派生类构造函数。这个调用顺序是固定的,不依赖于对象的实际类型,不会体现多态性。比如:
Derived d;
// 输出:
// Base constructor
// Derived constructor
2. 普通函数与多态性
- 普通函数默认非多态:
- 普通成员函数如果不声明为虚函数,调用时根据对象的静态类型决定。例如:
class Base {
public:
void nonVirtualFunc() {
std::cout << "Base::nonVirtualFunc" << std::endl;
}
};
class Derived : public Base {
public:
void nonVirtualFunc() {
std::cout << "Derived::nonVirtualFunc" << std::endl;
}
};
int main() {
Base* basePtr = new Derived();
basePtr->nonVirtualFunc(); // 输出:Base::nonVirtualFunc
delete basePtr;
return 0;
}
- 虚函数实现多态:
- 当普通成员函数声明为虚函数时,会根据对象的动态类型(实际指向的对象类型)来决定调用哪个函数版本,实现多态。例如:
class Base {
public:
virtual void virtualFunc() {
std::cout << "Base::virtualFunc" << std::endl;
}
};
class Derived : public Base {
public:
void virtualFunc() override {
std::cout << "Derived::virtualFunc" << std::endl;
}
};
int main() {
Base* basePtr = new Derived();
basePtr->virtualFunc(); // 输出:Derived::virtualFunc
delete basePtr;
return 0;
}
在上述代码中,通过将 virtualFunc
声明为虚函数,basePtr
虽然是 Base*
类型,但实际指向 Derived
对象,调用 virtualFunc
时会调用 Derived
类中的版本,体现了多态性。而普通非虚函数 nonVirtualFunc
则根据指针的静态类型(Base*
)调用 Base
类中的版本。