虚函数陷阱和使用基函数

Virtual function pitfalls and using base functions

本文关键字:基函数 函数 陷阱      更新时间:2023-10-16

我一直在为虚函数编写一个参考的东西,因为我总是忘记它们是如何工作的。以下是目前为止的内容:

#include <iostream>
using namespace std;
struct Base
{
    virtual void foo(int one = 1, int two = 2) = 0;
    virtual Base* bar() { cout << "Base barn"; return this; }
    virtual void baz(Base*) { cout << "Base bazn"; }
    virtual void boo(Base*) { cout << "Base boon"; }
    // Error: templates may not be virtual
    //template <typename T> virtual T bad(T t) {return t}
    virtual ~Base() {}
};
struct Derived : public Base
{
    void foo(int one = 3, int two = 4) 
        { cout << "one: " << one << " two: " << two << endl; }
    Derived* bar() { cout << "Derived barn"; return this; }
    void baz(Derived*) { cout << "Derived bazn"; }
    using Base::boo;
    void boo(Derived*) { cout << "Derived boon"; }
};
void example1()
{
    Base*       pB = new Derived();
    Derived*    pD = new Derived();
    // Foo is called with default parameters based on pointer
    pB->foo();  // one: 1 two: 2
    pD->foo();  // one: 3 two: 4
    // Bar is overridden because return type can be implicitly converted
    pB->bar();  // Derived bar
    pD->bar();  // Derived bar
    // Baz is not overridden because parameters differ
    pB->baz(pB);    // Base baz
    pB->baz(pD);    // Base baz
    //pD->baz(pB);  // invalid conversion from Base* to Derived*
    pD->baz(pD);    // Derived baz
    // Boo using test
    pB->boo(pB);    // Base boo
    pB->boo(pD);    // Base boo
    pD->boo(pB);    // Base boo
    pD->boo(pD);    // Derived boo
    delete pB;
    delete pD;
}
struct Base2
{
    void foo(int one = 1, int two = 2) { foo_impl(one, two); }
    virtual ~Base2() {}
private:
    virtual void foo_impl(int one, int two) = 0;
};
struct Derived2 : public Base2
{
private:
    void foo_impl(int one, int two) 
        { cout << "one: " << one << " two: " << two << endl; }
};
void example2()
{
    Base2*       pB = new Derived2();
    Derived2*    pD = new Derived2();
    // Now one set of default parameters exists
    pB->foo();  // one: 1 two: 2
    pD->foo();  // one: 1 two: 2
    delete pB;
    delete pD;
}
int main()
{
   example1();
   example2();
   return 0;
}

我对boo()函数感到困惑。在我看来,pB->boo(pD)接近example1()的末尾应该调用函数的覆盖版本,但它调用基本版本。为什么?如果你能解释一下哪里需要所有的using以及它是如何工作的,那将是有帮助的,谢谢。

另外,如果你在使用虚拟函数时想到了其他需要注意的陷阱,也可以把它们贴出来。谢谢。

可以从baz函数中看到答案。正如您在评论中注意到的那样,派生类的baz不会覆盖基类的版本,因为参数不同。boo也是如此。

你的using Base::boo;语句不会以任何方式改变boo不覆盖。相反,它只是将基版本引入派生类的作用域。本质上,就好像派生类有两个函数的重载。

然而,对于pB->boo(pD);,重载是不相关的,因为指针是根据Base类型的。所以编译器只知道基类的boo函数。因此,由于没有重写boo,它最终调用基本版本。