【Exceptional C++(10)】改写虚函数
2018-01-29 本文已影响6人
downdemo
问题
- 下列代码期望打印出什么结果,实际打印结果是什么
#include <iostream>
#include <complex>
using namespace std;
class Base
{
public:
virtual void f(int);
virtual void f(double);
virtual void g(int i = 10);
};
void Base::f(int)
{
cout << "Base::f(int)" << endl;
}
void Base::f(double)
{
cout << "Base::f(double)" << endl;
}
void Base::g(int i)
{
cout << i << endl;
}
class Derived : public Base
{
public:
void f(complex<double>);
void g(int i = 20);
};
void Derived : f(complex<double>)
{
cout << "Derived::f(complex)" << endl;
}
void Derived::g(int i)
{
cout << "Derived::g()" << i << endl;
}
int main()
{
Base b;
Derived d;
Base* pb = new Derived;
b.f(1.0);
d.f(1.0);
pb->f(1.0);
b.g();
d.g();
pb->g();
delete pb;
}
解答
- delete pb不安全,因为Base没有虚析构函数
- 三个常见术语:重载、重写和隐藏
- 重载(overload):同一个scope中有另一个同名函数
- 重写(override):派生类中提供一个和基类名称相同,参数类型相同的虚函数
- 隐藏(hide):内层scope覆盖外层scope的同名式
- Derived::f(complex<double>)不会重载Base::f,而是隐藏,所以Base::f(int)和Base::f(double)在派生类中都不可见,如果希望可见,用using声明式using Base::f
- Derived::g重写了Base::g,但也改变了默认参数,虽然这是合法的,但是不要这样做,会产生迷惑性
- 再来看最后输出的结果
int main()
{
Base b;
Derived d;
Base* pb = new Derived;
b.f(1.0);
// 调用Base::f(double)
d.f(1.0);
// 这次调用Derived::f(complex<double>),因为Base::f被隐藏了
// complex提供了隐式转换,实际相当于Derived::f(complex<double>(1.0))
pb->f(1.0);
// 调用Base::f(double),因为派生类没有Derived::f(double)
b.g();
// 调用Base::g(10)
d.g();
// 调用Derived::g(20)
pb->g();
// 调用Derived::g(10),因为默认参数由静态类型(pb是Base)决定
delete pb;
}