虚函数陷阱和使用基函数

时间:2014-08-05 22:15:59

标签: c++ polymorphism using virtual-functions

我一直在编写虚拟函数的参考资料,因为我总是忘记它们的工作方式。以下是我到目前为止的情况:

#include <iostream>

using namespace std;

struct Base
{
    virtual void foo(int one = 1, int two = 2) = 0;

    virtual Base* bar() { cout << "Base bar\n"; return this; }

    virtual void baz(Base*) { cout << "Base baz\n"; }

    virtual void boo(Base*) { cout << "Base boo\n"; }

    // 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 bar\n"; return this; }

    void baz(Derived*) { cout << "Derived baz\n"; }

    using Base::boo;
    void boo(Derived*) { cout << "Derived boo\n"; }
};

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的所需位置及其工作原理,那将非常有用,谢谢。

此外,如果你能想到在使用虚拟功能时需要注意的其他陷阱,也可以随意发布。感谢。

1 个答案:

答案 0 :(得分:2)

可以通过baz函数看到答案。正如您在注释中所述,派生类的baz不会覆盖基类的版本,因为参数不同。这与boo的情况相同。

您的using Base::boo;语句不会以任何方式更改boo而不会覆盖。相反,它只是将基本版本带入派生类的范围。从本质上讲,就好像派生类有两个函数的重载

然而,pB->boo(pD);重载是不相关的,因为指针是按Base输入的。所以编译器只知道基类的boo函数。因此,由于没有任何内容覆盖boo,它最终会调用基本版本。