📅  最后修改于: 2023-12-03 15:13:58.336000             🧑  作者: Mango
在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++中,虚函数是一种允许在派生类中重新定义的特殊函数。为了在实现多态的同时,正确地使用基类和派生类的成员变量,我们需要声明相应的函数为虚函数。同时,我们需要在虚函数的基类中实现虚函数,这样就能够使用动态绑定的特性,在运行时动态地调用派生类中的版本。