📅  最后修改于: 2023-12-03 15:13:58.329000             🧑  作者: Mango
在C++中,虚函数是一种特殊的成员函数,通过关键字virtual
定义。虚函数能够在父类和子类中具有不同的实现,使得程序的可扩展性更高。
然而,在使用虚函数时,我们可能会遇到一些问题,其中一个问题就是虚函数与构造函数结合使用时的坑点。
在C++中,如果一个类中定义了虚函数,那么在创建其子类对象时,该子类对象的虚函数表会指向其父类的虚函数表,然后再根据子类的实现进行修改。这个过程发生在子类对象完全构造好之后。
但是,在构造子类对象时,由于父类的构造函数会先于子类的构造函数被调用,因此在父类的构造函数中调用虚函数时,子类虚函数表还未被修改,因而子类的实现还未生效,只能调用父类的实现。
以下是一个简单的示例代码:
#include <iostream>
class Base {
public:
Base() {
func();
}
virtual void func() {
std::cout << "In Base" << std::endl;
}
};
class Derived : public Base {
public:
Derived() {}
void func() override {
std::cout << "In Derived" << std::endl;
}
};
int main() {
Derived d;
return 0;
}
在这个示例中,我们定义了一个Base类和一个Derived类继承自Base类。在Base类中定义了一个虚函数func()
,在Derived类中重写了该虚函数。
在执行main()
函数时,我们创建了一个Derived类的对象d。在创建对象的过程中,先调用了Base类的构造函数,输出的结果是:
In Base
我们期望的结果是:
In Derived
这说明在调用父类构造函数中的虚函数时,不会调用子类的实现,而是始终调用父类的实现。
为了避免这个问题,我们需要在父类的构造函数中避免调用虚函数。我们可以将虚函数的调用放到父类构造函数之后,或者在子类的构造函数中调用虚函数。
以下是利用初始化列表和构造函数重载避免这个问题的示例代码:
#include <iostream>
class Base {
public:
Base() {}
Base(bool) {
func();
}
virtual void func() {
std::cout << "In Base" << std::endl;
}
};
class Derived : public Base {
public:
Derived() : Base(true) {}
void func() override {
std::cout << "In Derived" << std::endl;
}
};
int main() {
Derived d;
return 0;
}
在这个示例中,我们定义了两个构造函数Base()
和Base(bool)
。在函数Base(bool)
中调用了虚函数func()
。在子类的构造函数中,我们使用初始化列表调用了Base(bool)
,这样就避免了在父类构造函数中调用虚函数了。
输出的结果是:
In Derived
这样,我们就避免了虚函数与构造函数结合使用时的坑点。