小编mic*_*ies的帖子

对虚函数和派生类的混淆

我想了解下面的代码:

#include<iostream>
using namespace std;
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;
    d->f(3.14F);
    b->f(3.14F);
}
Run Code Online (Sandbox Code Playgroud)

这打印

Derived::f(int)
Base::f(float)
Run Code Online (Sandbox Code Playgroud)

我不确定为什么.

第一个调用d-> f(3.14F)调用Derived中的函数f.我不是100%肯定为什么.我看了一下(http://en.cppreference.com/w/cpp/language/implicit_cast),其中说:

浮点类型的prvalue可以转换为任何整数类型的prvalue.小数部分被截断,即,小数部分被丢弃.如果该值不适合目标类型,则行为未定义

对我来说,你不能这样做,因为浮点数不适合int.为什么允许这种隐式转换?

其次,即使我只接受上面的判断,第二次调用b-> f(3.14F)也没有意义.b-> f(3.14F)正在调用虚函数f,因此动态解析它以调用与b指向的对象的动态类型相关联的f(),这是一个Derived对象.因为我们被允许将3.14F转换为int,因为第一个函数调用表明这是合法的,这(我的理解)应该再次调用Derived :: f(int)函数.然而它调用了Base类中的函数.那么为什么呢?

编辑:这是我如何理解并向自己解释的.

b是指向Base对象的指针,因此我们只能使用b来访问Base对象的成员,即使b确实指向某个Derived对象(这是标准的OO /继承内容).

此规则的唯一例外是Base的成员函数声明为virtual.在这种情况下,Derived对象可以覆盖此函数,通过使用完全相同的签名提供另一个实现.如果发生这种情况,那么即使我们碰巧通过指向Base对象的指针访问成员函数,也会在运行时调用此Derived实现.

现在,在上面的代码片段中,我们没有任何重写,因为B :: f和D :: f的签名是不同的(一个是浮点数,另一个是int).因此,当我们调用b-> f(3.14F)时,唯一考虑的函数是原始的B :: f,这就是所谓的.

c++ virtual-functions name-hiding

4
推荐指数
1
解决办法
1498
查看次数

标签 统计

c++ ×1

name-hiding ×1

virtual-functions ×1