有人能解释为什么下面代码的结果会是“B类:: 1”吗?
为什么派生类的虚方法使用基类的默认参数而不是自己的默认参数?对我来说这很奇怪。提前谢谢!
代码:
#include <iostream>
using namespace std;
class A
{
public:
virtual void func(int a = 1)
{
cout << "class A::" << a;
}
};
class B : public A
{
public:
virtual void func(int a = 2)
{
cout << "class B::" << a;
}
};
int main()
{
A * a = new B;
a->func();
return 0;
}
答案 0 :(得分:6)
因为默认参数是根据this
的静态类型解析的(即变量本身的类型,如A&
中的A& a;
)。
稍微修改您的示例:
#include <iostream>
class A
{
public:
virtual void func(int a = 1)
{
std::cout << "class A::" << a << "\n";
}
};
class B : public A
{
public:
virtual void func(int a = 2)
{
std::cout << "class B::" << a << "\n";
}
};
void func(A& a) { a.func(); }
int main()
{
B b;
func(b);
b.func();
return 0;
}
我们观察到以下输出:
class B::1
class B::2
ideone的行动。
出于这个原因,不建议虚函数更改默认值。不幸的是,我不知道任何编译器警告这个结构。
技术说明是有两种处理默认参数的方法:
void A::func() { func(1); }
a.func()
=&gt;添加缺少的参数a.func(/*magic*/1)
如果它是前者(假设A::func
也被声明为virtual
),那么它会像您期望的那样工作。然而,后一种形式是当选的,或者是因为当时没有预见virtual
的问题,或者因为它们被认为是无关紧要的(如果有的话......)。
答案 1 :(得分:5)
因为默认值在编译期间被替换并且取自声明,而在运行时确定要调用的实函数(A :: func或B :: func)。
答案 2 :(得分:5)
因为C ++中的多态性在运行时生效,而默认参数的替换在编译时生效。在编译时,编译器不知道(并且不应该知道)指针a
指向的对象的动态类型。因此,它为a
知道的唯一类型采用默认参数,在您的示例中为A *
。
(顺便提一下,这也是接口/头文件中而不是实现/定义中给出默认参数的原因。编译器从不在实现的机器代码中插入默认参数,但只在调用者的中从技术上讲,默认参数是调用者的属性;调用者不知道 - 也不应该知道 - 对象的动态类型。)