基类指针只能调用基类的成员函数,不能调用派生类的成员函数。
如果在基类的成员函数前加virtual 关键字,把它声明为虚函数,基类指针就可以调用派生类中同名的成员函数,通过派生类中同名的成员函数,就可以访问派生对象的成员变量。
有了虚函数,基类指针指向基类对象时就使用基类的成员函数和数据,指向派生类对象时就使用派生类的成员函数和数据,基类指针表现出了多种形式,这种现象称为多态。
基类引用也可以使用多态。
注意:
1)只需要在基类的函数声明中加上virtual关键字,函数定义时不能加。
2)在派生类中重定义虚函数时,函数特征要相同。
3)当在基类中定义了虚函数时,如果派生类没有重定义该函数,那么将使用基类的虚函数。
4)在派生类中重定义了虚函数的情况下,如果想使用基类的虚函数,可以加类名和域解析符。
5)如果要在派生类中重新定义基类的函数,则将它设置为虚函数;否则,不要设置为虚函数,有两方面的好处:首先效率更高;其次,指出不要重新定义该函数。
下面是一个C++示例代码,演示了使用虚函数实现多态:
#include <iostream>
class Base {
public:
int baseValue;
// 基类中的虚函数
virtual void show() {
std::cout << "Base::show() - baseValue: " << baseValue << std::endl;
}
};
class Derived : public Base {
public:
int derivedValue;
// 在派生类中重定义虚函数
void show() override {
std::cout << "Derived::show() - derivedValue: " << derivedValue << std::endl;
}
};
int main() {
Base baseObj;
baseObj.baseValue = 10;
Derived derivedObj;
derivedObj.baseValue = 20;
derivedObj.derivedValue = 30;
// 基类指针指向基类对象
Base* basePtr = &baseObj;
basePtr->show(); // 调用Base::show()
// 基类指针指向派生类对象
basePtr = &derivedObj;
basePtr->show(); // 调用Derived::show(),因为show是虚函数
// 基类引用引用派生类对象
Base& baseRef = derivedObj;
baseRef.show(); // 调用Derived::show(),因为show是虚函数
return 0;
}
解释
- 虚函数的声明:在基类
Base
中,show
函数被声明为虚函数virtual void show()
。 - 派生类中的虚函数重定义:在派生类
Derived
中,重定义了show
函数,并加上override
关键字,以确保它重写了基类的虚函数。 - 基类指针指向基类对象:当
basePtr
指向baseObj
时,调用basePtr->show()
,输出基类的show
函数结果。 - 基类指针指向派生类对象:当
basePtr
指向derivedObj
时,调用basePtr->show()
,输出派生类的show
函数结果。这就是多态的体现。 - 基类引用引用派生类对象:当
baseRef
引用derivedObj
时,调用baseRef.show()
,同样输出派生类的show
函数结果。
注意事项
- 只需要在基类的函数声明中加上
virtual
关键字,函数定义时不能加。 - 在派生类中重定义虚函数时,函数特征要相同(包括参数和返回类型)。
- 如果派生类没有重定义基类的虚函数,将使用基类的虚函数。
- 在派生类中重定义虚函数时,如果想使用基类的虚函数,可以加类名和域解析符来调用(例如
Base::show()
)。 - 只有需要在派生类中重新定义基类函数时,才将它设置为虚函数,否则不要设置为虚函数,以提高效率和明确意图。