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

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

C++虚函数问题4

在C++中,虚函数是一种在派生类中可以被重新定义的特殊函数。本文将探讨虚函数的一个常见问题:如何在实现多态的同时,同时使用基类和派生类的成员变量。

问题描述

考虑如下的基类 Base 和它的一个派生类 Derived。假设它们都有一个名为 value_ 的整型成员变量。

class Base {
public:
    virtual ~Base() {}
    
    void print() {
        std::cout << "Base: " << value_ << std::endl;
    }
    
protected:
    int value_ = -1;
};

class Derived : public Base {
public:
    void print() {
        std::cout << "Derived: " << value_ << std::endl;
    }
    
protected:
    int value_ = 1;
};

Base 中,我们定义了一个虚函数 print(),用来打印 value_ 的值。派生类 Derived 中重载了 print() 函数,打印的是自己的 value_ 变量。

现在,我们定义了一个函数 print_value(),它的参数是一个 Base 类型的指针。我们希望能够在不知道该指针的实际类型的情况下,调用正确的 print() 函数。

void print_value(Base* base) {
    base->print();
}

int main() {
    Base* p = new Base();
    p->print(); // "Base: -1"
    
    Derived* q = new Derived();
    q->print(); // "Derived: 1"
    
    print_value(p); // "Base: -1"
    print_value(q); // "Base: -1"
    
    delete p;
    delete q;
    return 0;
}

这里的问题在于,无论参数 base 的实际类型是 Base 还是 Derived,调用 print() 函数时都会调用 Base 类中的版本,因为对于编译器来说,这个指针的类型是 Base*。因此,上述代码的输出都是 "Base: -1"

解决方案

为了解决上述问题,我们可以在虚函数的基类中将该函数声明为虚函数,这样我们就能够利用动态绑定的特性,在运行时选择使用哪个类的方法。

class Base {
public:
    virtual ~Base() {}
    
    virtual void print() { // 加上 virtual 关键字
        std::cout << "Base: " << value_ << std::endl;
    }
    
protected:
    int value_ = -1;
};

class Derived : public Base {
public:
    void print() {
        std::cout << "Derived: " << value_ << std::endl;
    }
    
protected:
    int value_ = 1;
};

在这里,我们为 Base 类中的 print() 函数添加了 virtual 关键字,这样它就成为了一种虚函数。当我们在派生类中重新定义了这个函数时,该虚函数就会被动态绑定,使得能够正确地调用派生类中的版本。

void print_value(Base* base) {
    base->print();
}

int main() {
    Base* p = new Base();
    p->print(); // "Base: -1"
    
    Derived* q = new Derived();
    q->print(); // "Derived: 1"
    
    print_value(p); // "Base: -1"
    print_value(q); // "Derived: 1"
    
    delete p;
    delete q;
    return 0;
}

现在,我们在运行 print_value() 函数时能够正确地调用派生类中的版本,而不是基类中的版本。因此,上述代码的输出就变成了:

Base: -1
Derived: 1
Base: -1
Derived: 1
总结

在C++中,虚函数是一种允许在派生类中重新定义的特殊函数。为了在实现多态的同时,正确地使用基类和派生类的成员变量,我们需要声明相应的函数为虚函数。同时,我们需要在虚函数的基类中实现虚函数,这样就能够使用动态绑定的特性,在运行时动态地调用派生类中的版本。