派生类虚函数调用基类版本

C++ primer 这本书上有这么两句话“派生类虚函数调用基类版本时,必须显式使用作用域操作符。如果派生类函数忽略了这样做,则函数调用会在运行时确定并且将是一个自身调用,从而导致无穷递归。”

这句话应该这样理解:

当你实现派生类虚函数B : foo时,如果函数体内需要调用基类的虚函数版本时,需要显式使用基类的作用域操作符A::foo(),否则foo()就会在派生类作用域内调用派生类版本的虚函数,这样会导致无穷递归。

就是自己在调用自己呀,没有指明调用的是基类的虚函数,自动认为是调用派生类的虚函数,然后就再次调用了,一直进行下去了


struct A
{
virtual void foo(void) { }
}
struct B: public A
{
void foo(void)
{
foo(); // 递归调用自己,即 B::foo()
A::foo(); // 明确告诉编译器,调用的是 A::foo(), 而不是自己
}
}





<think>好的,用户现在问的是派生类如何调用基类中的虚函数。我需要先回忆一下C++虚函数的基本机制。虚函数允许派生类重写基类的实现,但有时候可能需要显式调用基类版本,尤其是在派生类的覆盖函数中需要基类功能时。 首先,用户可能已经知道虚函数的基本用法,但可能在实践中遇到了问题,比如如何在派生类的方法中调用基类被覆盖的虚函数。我需要确认调用方式是否正确,比如使用作用域运算符(::)来指定基类。 接下来,我需要考虑用户可能的场景。比如,他们可能在设计类层次结构时,希望扩展基类的功能而不是完全替换,这时候显式调用基类方法就很重要。例如,在重写的函数中先执行基类的操作,再添加派生类特有的代码。 还要注意可能的错误情况,比如忘记使用基类名限定导致递归调用,或者多重继承时基类名称冲突的情况。需要提醒用户正确的作用域解析方法,以及如何处理多继承下的情况。 另外,用户可能对虚函数表(vtable)机制不太清楚,但在这个问题中可能不需要深入讲解,除非用户进一步提问。保持回答简洁,重点放在调用方法上。 需要举一个简单的例子,展示派生类中使用Base::function()来调用基类虚函数。同时,说明在构造函数和析构函数中调用虚函数的注意事项,因为此时对象的动态类型可能不同,导致未定义行为。 最后,总结关键点,强调作用域运算符的使用和适用场景,确保用户能够正确应用在实际编码中。</think>--- #### **如何调用基类虚函数** 在C++中,当派生类重写(override)基类虚函数时,若需要**显式调用基类版本虚函数**,可以通过以下两种方式实现: --- ### **1. 使用作用域运算符(`::`)** 通过**基类名称 + 作用域运算符**直接指定调用基类的函数版本。 ```cpp class Base { public: virtual void func() { std::cout << "Base::func()" << std::endl; } }; class Derived : public Base { public: void func() override { // 重写基类虚函数 // 调用基类版本的func() Base::func(); // 显式指定基类作用域 std::cout << "Derived::func()" << std::endl; } }; int main() { Derived d; d.func(); // 输出 Base::func() 和 Derived::func() return 0; } ``` --- ### **2. 通过基类指针/引用调用** 若通过基类指针或引用操作派生类对象,默认会触发**动态绑定**(调用派生类重写的函数)。若需要强制调用基类版本,仍需使用作用域运算符。 ```cpp int main() { Derived d; Base* ptr = &d; ptr->func(); // 动态绑定:调用Derived::func() ptr->Base::func(); // 强制调用Base::func() return 0; } ``` --- ### **关键点总结** | 场景 | 调用方式 | 说明 | |-----------------------|------------------------------|----------------------------------------------------------------------| | **派生类内部调用** | `Base::func()` | 在派生类成员函数中直接通过基类名限定 | | **外部通过对象调用** | `obj.Base::func()` | 若对象是派生类实例,需显式指定基类作用域 | | **通过基类指针/引用** | `ptr->Base::func()` | 即使指针指向派生类对象,仍可强制调用基类版本 | | **构造函数/析构函数** | 直接写`Base::func()` | 在构造/析构函数中,虚函数机制会暂时失效,直接调用基类版本更安全 | --- #### **注意事项** 1. **避免递归调用** 若在派生类中直接写 `func()` 而不是 `Base::func()`,会导致无限递归: ```cpp // 错误示例 void Derived::func() { func(); // 实际调用Derived::func(),导致递归 } ``` 2. **多重继承的歧义性** 若派生类继承自多个基类,且基类有同名函数,需明确指定基类名称: ```cpp class Base1 { virtual void func(); }; class Base2 { virtual void func(); }; class Derived : public Base1, public Base2 { void func() override { Base1::func(); // 明确调用Base1的版本 Base2::func(); // 明确调用Base2的版本 } }; ``` 3. **纯虚函数调用** 若基类虚函数是纯虚函数(如 `virtual void func() = 0;`),派生类必须实现它,但实现后仍可通过 `Base::func()` 调用(需提供基类默认实现)。 --- #### **示例:扩展基类功能** ```cpp class Shape { public: virtual void draw() { std::cout << "绘制基础图形" << std::endl; } }; class Circle : public Shape { public: void draw() override { Shape::draw(); // 先调用基类绘制逻辑 std::cout << "绘制圆形" << std::endl; // 扩展功能 } }; int main() { Circle c; c.draw(); // 输出:绘制基础图形 → 绘制圆形 return 0; } ``` --- ### **总结** - **核心方法**:使用 `基类名::虚函数名()` 显式调用基类虚函数。 - **应用场景**:在派生类中复用基类逻辑,或在需要强制调用基类实现时使用。 - **底层原理**:虚函数表(vtable)机制下,显式调用会绕过动态绑定,直接定位基类函数地址。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值