📜  C++ |虚函数|问题3(1)

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

C++ | 虚函数 | 问题3

在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

这样,我们就避免了虚函数与构造函数结合使用时的坑点。