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

#include <iostream>
using namespace std;

class Base
{
public:
    virtual void foo(void) { std::cout << "Base::foo()" << std::endl; }
    virtual void doo(void) { std::cout << "Base::doo()" << std::endl; }
};

class Derived: public Base
{
public:
    void foo(void)
    {
        //foo();        // 错误。递归调用自己,即 Derived::foo()
        Base::foo();    // 明确告诉编译器,调用的是 Base::foo(), 而不是自己
        std::cout << "Derived::foo()" << std::endl;
    }

    virtual void doo(void)
    {
        Base::doo();
        std::cout << "Derived::doo()" << std::endl;
    }
};

class Derived2 : public Derived
{
    virtual void doo(void)
    {
        Derived::doo();
        std::cout << "Derived2::doo()" << std::endl;
    }
};

class Derived3 : public Derived2
{
    virtual void foo(void)
    {
        Derived2::foo();
        std::cout << "Derived3::foo()" << std::endl;
    }
};

int main(/* int argc, char *argv[] */)
{
    Derived3 *d = new Derived3;
    Base *b = d;

    b->foo();
    cout << "------------------------" << endl;
    b->doo();

    b = nullptr;
    delete d;
    d = nullptr;

    return 0;
}

程序输出:

结论:

1.派生类虚函数调用基类版本时,必须显式使用作用域操作符。
2.多态时,在虚函数继承链上,如果某个子类没有覆盖虚函数,则调用亲缘最近的父类版本。最佳做法,还是每个子类都实现。


参考资料:

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

http://blog.youkuaiyun.com/glx2012/article/details/8254623

<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)机制下,显式调用会绕过动态绑定,直接定位基类函数地址。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值