我一直在编写虚拟函数的参考资料,因为我总是忘记它们的工作方式。以下是我到目前为止的情况:
#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
的所需位置及其工作原理,那将非常有用,谢谢。
此外,如果你能想到在使用虚拟功能时需要注意的其他陷阱,也可以随意发布。感谢。
答案 0 :(得分:2)
可以通过baz
函数看到答案。正如您在注释中所述,派生类的baz
不会覆盖基类的版本,因为参数不同。这与boo
的情况相同。
您的using Base::boo;
语句不会以任何方式更改boo
而不会覆盖。相反,它只是将基本版本带入派生类的范围。从本质上讲,就好像派生类有两个函数的重载。
然而,pB->boo(pD);
重载是不相关的,因为指针是按Base
输入的。所以编译器只知道基类的boo
函数。因此,由于没有任何内容覆盖boo
,它最终会调用基本版本。