C++ 虚拟方法未按预期调用

Posted

技术标签:

【中文标题】C++ 虚拟方法未按预期调用【英文标题】:C++ virtual method not called as expected 【发布时间】:2017-01-04 06:44:21 【问题描述】:

我正在摆弄虚拟方法的正确覆盖。我链接了一些构造函数,并在基类构造函数中调用了一个虚拟方法。

调用链应该如下:

B(p)->A(p)->B.foo(p)

调用链在 C++ 中:

B(p)->A(p)->A.foo(p)

调用链在 C# 中:

B(p)->A(p)->B.foo(p)

也就是说,在 C# 中,行为符合预期,而在 C++ 中则不然。

C++ 代码:

#include <cstdio>

class A 
public:
  A();
  A(int);

  virtual void foo(int s);
;

class B : public A 
public:
  B();
  B(int s) : A(s) ;

  virtual void foo(int s) override;
;

A::A() 
  std::printf("A\r\n");
;

A::A(int s) : A() 
  std::printf("A: %d\r\n", s);
  foo(s);
;

void A::foo(int s) 
  std::printf("A::foo(%d)\r\n", s);


B::B() : A()
  std::printf("B\r\n");
;

void B::foo(int s) 
  std::printf("B::foo(%d)\r\n", s);


int main(int argc, char* argv[]) 
  B b(2);

输出:

A
A: 2
A::foo(2)

C#代码:

using System;

namespace demo 
class A
  public A() 
    Console.WriteLine("A");
  

  public A(int s) : this()
    Console.WriteLine("A: " + s.ToString());
    foo(s);
  

  public virtual void foo(int s) 
    Console.WriteLine(string.Format("A:foo(0)", s));
  


class B : A
  public B() : base() 
    Console.WriteLine("B");
  

  public B(int s) : base(s) 
  

  public override void foo(int s) 
    Console.WriteLine(string.Format("B:foo(0)", s));
  


  static class Run 
    static void Main() 
      new B(2);
    
  

输出:

A
A: 2
B::foo(2)

为什么在 C++ 中不调用类 B 的重写方法?如何正确覆盖它?

【问题讨论】:

在构造函数完成之前,虚拟调度不起作用。 ***.com/questions/962132/… 您说过 C++ 和 C# 的输出是相同的。你的意思是在 C# 中它调用 B::foo(2)? 不,输出不一样,C# 的行为符合预期,C++ 不是。我将输出添加到问题中。 【参考方案1】:

这正是 C++ 的工作方式。虚函数在对象构造和销毁过程中不具有虚拟行为。

【讨论】:

为什么不呢?他们这样做 :) ,只是他们使用了作者没有预料到的 vtables

以上是关于C++ 虚拟方法未按预期调用的主要内容,如果未能解决你的问题,请参考以下文章

调用 setGridLinesVisible(true) 时,GridPane 布局调试行未按预期显示

Spark 过滤器未按预期工作。“列”对象不可调用

PostAsJsonAsync 未按预期运行

react-redux s-s-r 异步 api 调用未按预期工作

QTableWidget::row() 未按预期运行

Nativescript-vue $emit 未按预期工作