【问题标题】:Why does the program writes output like this?为什么程序会这样写输出?
【发布时间】:2014-09-03 22:35:45
【问题描述】:

我想知道为什么这个c++程序的输出是X:f1?是否调用了 y 对象,调用 Y 的 f1() 是否合乎逻辑?不应该继承吗?我很困惑...

    class X {
    public:
        void f1() { cout<<"X:f1"<<endl;}
    };
    class Y : public X {
    public:
        void f1() { cout<<"Y:f1"<<endl;}
    };
    Y* y = new Y();
    void f(X* x) { x -> f1(); }
    int main () { f (y);
    system("pause");
    return 1;
    }

以及如何更改 f() 函数的主体和在输出中获取 Y:f1 所需的参数?

【问题讨论】:

  • 将函数f1()声明为virtual
  • 如果您来自 Java、Python 等所有实例方法都是虚拟的语言,那么您应该阅读它们。

标签: c++ function inheritance


【解决方案1】:

由于X::f1 不是virtual,对它的调用是静态调度的,即在这种情况下,它们是基于x 的静态类型(即X)而不是动态类型调度的它(在这种情况下是Y)。

换一种说法,因为X::f1 不是virtual,所以当您调用f(y)x 指向Y 的实例这一事实没有被考虑在内——编译器调度所有调用到X::f1Xf1,不管x 指向的对象的动态(即运行时)类型。

与其他语言(例如 Java)不同,C++ 中的成员函数默认不是 virtual - 您必须明确指定您希望子类能够覆盖它们。

要获得您期望的输出,您需要将 virtual 限定符添加到 X::f1 - 您无法按照您的建议仅通过更改 f 的主体来实现您想要的,因为您正在丢弃有关x 的动态类型的信息,但在这种特殊情况下,您可以更改f 的参数以接受Y* 而不是X*

【讨论】:

  • 是的,你是对的。非常感谢,我只是忘记了那个“微小”的细节 :) 干杯!
  • @anicicn 这肯定不是一个微小的细节,而是c++编程中非常基本的一点!
  • 它真的回答了这个问题吗?
  • @Slava:我添加了一些内容来更明确地回答。
  • @StuartGolodetz 我明白了,但他的问题很具体 - 如何更改功能f()
【解决方案2】:

您遇到此问题是因为该函数未声明为虚拟函数。您需要将virtual 限定符添加到Xf1 以允许子类覆盖它。

class X {
public:
    virtual void f1() { cout<<"X:f1"<<endl;}
};

class Y : public X {
public:
    virtual void f1() { cout<<"Y:f1"<<endl;}
};

如果你不这样做,Yf1 只有在编译器知道对象的类型时才会被调用。当您将其转换为X* 时,情况并非如此。这是您观察到的行为:

Y* y = new Y;
y->f1(); // prints "Y:f1"
X* x = y;
x->f1(); // prints "X:f1"!

【讨论】:

  • 感谢您的回答:)
【解决方案3】:

以及如何更改 f() 函数的主体和获取所需的参数 Y:f1 在输出端?

您的问题的实际答案是:

void f(Y* y) { y -> f1(); }

虽然在派生类中存在同名同签名的非虚方法并没有太大的意义,除了会产生难以捕捉的问题。

【讨论】:

    【解决方案4】:

    我以这种方式在我的编译器中尝试了你的代码

    #include<iostream>
    using namespace std;
    class X {
    public:
         virtual void f1() { cout<<"X:f1"<<endl;}
      // ^^^^^^^ Note my changes here!
    };
    class Y : public X {
    public:
        void f1() { cout<<"Y:f1"<<endl;}
    };
    
    Y* y = new Y();
    void f(X* x) { x -> f1(); }
    
    int main () {
        f(y);
        return 1 ;
    }
    

    输出是Y:F1 而不是X:F1 你说再试一次,

    【讨论】:

    • 这不是我发布的代码。您插入了我在上面的帖子中没有的虚拟。
    • @omar-khaled 下次第一枪做得更好!
    猜你喜欢
    • 2013-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多