3
class Base {
public:
virtual void f(float) { cout << "Base::f(float)\n"; }
};
class Derived : public Base {
public:
virtual void f(int) { cout << "Derived::f(int)\n"; }
};
int main() {
Derived *d = new Derived();
Base *b = d;
b->f(3.14F);
d->f(3.14F);
}

-C++ 不支持逆变返回类型,因此 f(int) 不会覆盖 f(float)

-C++ 支持多态,因此 d 和 b 都应该指向派生类的 vtable。

派生类的 -vtable 类似于 0: f(float), 1: f(int) 等。

我对这个问题的回答是 Base::f(float) 被调用了两次,但答案是:

基数::f(float) 派生::f(int)

为什么会这样?从不同的指针访问派生类是否强制执行某些规则?据我所知,对象切片仅在使用 copy-ctor 或 copy-assignment 时发生,带有指针,它们都应该指向同一个 vtable。

4

2 回答 2

3

不同类中的方法不会一起重载;定义另一个f()inDerived可以防止Base在重载解决期间考虑另一个 in。

当您想要添加新的重载而不隐藏基类中定义的重载时,您需要显式地将基定义引入派生类。

public:
    using Base::f;
于 2014-11-08T03:36:15.310 回答
1

我对此的看法是,当您调用时,float 会隐式转换为 intd->f(3.14F)

您的Derived班级实际上有 2 个 f() 条目

void f(int);
void f(float);

这通过带有 -fdump-class-hierarchy 标志的 g++ 得到确认。我们可以看到输出如下:

Vtable for Base
Base::_ZTV4Base: 3u entries
0     (int (*)(...))0
4     (int (*)(...))(& _ZTI4Base)
8     (int (*)(...))Base::f

Vtable for Derived
Derived::_ZTV7Derived: 4u entries
0     (int (*)(...))0
4     (int (*)(...))(& _ZTI7Derived)
8     (int (*)(...))Base::f
12    (int (*)(...))Derived::f

由于定义不匹配,您的Derived类不会触及基类中的 f 函数。代码编译是因为在 float 和 int 之间存在隐式转换。

尝试以下

class Derived : public Base {
public:
virtual void f(std::string) { cout << "Derived::f(string)\n"; }
};

然后此代码将不会编译,因为 Derived:f(...) 将隐藏 Base::f(...) 定义。这通常被称为继承阴影。

因此调用 b->f(3.14F) 将在 Base 表中解析,而 d->f(3.14F) 将在 Derived 表中解析,它隐藏了 Base。

于 2014-11-08T04:27:14.840 回答