我正在阅读一个C ++难题:http://gotw.ca/gotw/005.htm
我不理解他对静态与动态重载决策(或默认参数)的解释,所以我试着提炼出问题并自己写一些测试:
class Base {
public:
virtual void foo() {cout << "base/no parameters" << endl;}
virtual void foo(int a) {cout << "base/int" << endl;}
};
class Derived : public Base {
public:
void foo() {cout << "derived/no parameters" << endl;}
void foo(double a) {cout << "derived/int" << endl;}
};
int main() {
Base* ptr = new Derived;
ptr->foo();
ptr->foo(1.0);
}
输出结果为:
derived/no parameters
base/int
为了调用foo()
,C ++似乎认识到它指向Derived
,但在调用foo(1.0)
中,C ++没有看到void foo(double a)
函数在Derived
班?
在我看来,有一些竞争的想法,即C ++具有多态性,这解释了第一次调用,但是重载解析是在编译时完成的,这解释了第二次调用。
答案 0 :(得分:3)
这是 Function Hiding 的经典示例 当且仅当:
时,dervied类中的函数才会覆盖基类函数virtual
关键字至少存在于基类功能上。第二条规则有一个例外,允许 Covariant return types 。
鉴于以上两条规则:
派生类中的无参数foo()
函数覆盖基类foo()
,因此动态调度可以按预期工作。
带有一个参数的foo(double)
版本不会覆盖基类foo(int)
功能,它只是隐藏它。由于没有覆盖,因此没有动态分派,编译器只调用它在Base类范围内找到的foo(int)
函数。
答案 1 :(得分:2)
C ++在Derived类中没有看到
void foo(double a)
函数?
C ++确实看到了这个函数,但是由于函数签名的差异,与Base::foo
的{{1}}没有关联:
virtual
所以这里有virtual void Base::foo(int); // 'Base' signature
void Derived::foo(double); // 'Derived' signature
的两个重要事实:
Derived::foo(double)
Base::foo(int)
方法(即使使virtual
无效)第一点更重要,因为当你打电话时
virtual
使用 // 'ptr' refers 'Base' method signature; so 'double' implicitly converts to 'int'
ptr->foo(1.0);
指针。在vtable列表中,它只有一个Base
条目。因此它被称为。
答案 2 :(得分:2)
ptr
的类型为Base*
Base
中1.0
作为参数的唯一功能是virtual void foo(int a)
。
现在,请记住,对于要虚拟覆盖的函数,它需要完全匹配签名(减去差异,但不适用于您的情况)。您没有覆盖foo(int)
,但实际上是在创建新的foo(double)
。
答案 3 :(得分:1)
C ++无法在void foo(double a)
类中看到Derived
,因为 覆盖void foo(double a)
中带有签名Base
的虚拟函数class(你试图从中调用它)。
void foo(int a)
类中有Base
,但根据C ++的规则它是完全不同的函数。
另一方面,void foo()
类中的Derived
覆盖void foo()
类中的虚函数Base
,因为它们都具有相同的签名。 / p>
答案 4 :(得分:1)
class Base {
public:
virtual void foo() {cout << "base/no parameters" << endl;}
virtual void foo(int a) {cout << "base/int" << endl;}
};
class Derived : public Base {
public:
void foo() {cout << "derived/no parameters" << endl;}
void foo(int a) {cout << "derived/int" << endl;}
// then your derived class function will call
};
int main() {
Base* ptr = new Derived;
ptr->foo();
ptr->foo(1.0);
}
答案 5 :(得分:0)
静态与动态重载分辨率 !!!这是什么意思?
重载始终是静态绑定的,函数将在类中定义(不是一个函数在基类中,而其他函数在派生类中)。
所以foo(double a)和foo(int a)没有重载。同样,这些不会被覆盖,因为签名是不同的。这就是为什么没有为语句ptr-&gt; foo(1.0)发生虚拟机制的原因;