C++ 当从派生类的构造函数调用时,对虚拟函数的调用会步进错误的函数,而不是从父类调用时

C++ 当从派生类的构造函数调用时,对虚拟函数的调用会步进错误的函数,而不是从父类调用时,c++,constructor,gdb,virtual-functions,C++,Constructor,Gdb,Virtual Functions,我得到了下面的类结构(细节省略) 环境.h #include "SimEnv.h" class Environment : public SimEnv { public: virtual int functionA(int arg) { printf("I'm in functionA\n"); . . . } virtual int functionB(int arg) { printf("I'm in functionB\n"); . . .

我得到了下面的类结构(细节省略)

环境.h

#include "SimEnv.h"

class Environment : public SimEnv {
public:
  virtual int functionA(int arg) {
    printf("I'm in functionA\n");
    . . .
  }
  virtual int functionB(int arg) {
    printf("I'm in functionB\n");
    . . .
  }
};
#include "Environment.h"

class DerivedEnv : public Environment {
public:
  DerivedEnv(GrandParentClass* grandpaClass) : Environment() { . . . }
};
#include "GrandParentClass.h"
#include "Environment.h"

class ParentClass : public GrandParentClass {
public:
  ParentClass() {
    printf("In ParentClass constructor\n");
    m_pEnv = new DerivedEnv(this);
    m_pEnv->functionB(val);
  }
protected:
  Environment* m_pEnv;

  virtual void thisFunct() {
    printf("Calling functionB from ParentClass::thisFunct()\n");
    m_pEnv->functionB(val);
  }

};
#include "ParentClass.h"

class DerivedClass : public ParentClass {
public:
  DerivedClass() : ParentClass() {
    printf("In DerivedClass constructor\n");
    m_pEnv->functionB(val);
  }
  void thatFunct {
    printf("Calling functionB from DerivedClass::thatFunct()\n");
    m_pEnv->functionB(val);
  }
  void sim() {
    thisFunct();
    printf("Calling functionB from DerivedClass::sim()\n");
    m_pEnv->functionB(val);
  }

};
DerivedEnv.h

#include "SimEnv.h"

class Environment : public SimEnv {
public:
  virtual int functionA(int arg) {
    printf("I'm in functionA\n");
    . . .
  }
  virtual int functionB(int arg) {
    printf("I'm in functionB\n");
    . . .
  }
};
#include "Environment.h"

class DerivedEnv : public Environment {
public:
  DerivedEnv(GrandParentClass* grandpaClass) : Environment() { . . . }
};
#include "GrandParentClass.h"
#include "Environment.h"

class ParentClass : public GrandParentClass {
public:
  ParentClass() {
    printf("In ParentClass constructor\n");
    m_pEnv = new DerivedEnv(this);
    m_pEnv->functionB(val);
  }
protected:
  Environment* m_pEnv;

  virtual void thisFunct() {
    printf("Calling functionB from ParentClass::thisFunct()\n");
    m_pEnv->functionB(val);
  }

};
#include "ParentClass.h"

class DerivedClass : public ParentClass {
public:
  DerivedClass() : ParentClass() {
    printf("In DerivedClass constructor\n");
    m_pEnv->functionB(val);
  }
  void thatFunct {
    printf("Calling functionB from DerivedClass::thatFunct()\n");
    m_pEnv->functionB(val);
  }
  void sim() {
    thisFunct();
    printf("Calling functionB from DerivedClass::sim()\n");
    m_pEnv->functionB(val);
  }

};
ParentClass.h

#include "SimEnv.h"

class Environment : public SimEnv {
public:
  virtual int functionA(int arg) {
    printf("I'm in functionA\n");
    . . .
  }
  virtual int functionB(int arg) {
    printf("I'm in functionB\n");
    . . .
  }
};
#include "Environment.h"

class DerivedEnv : public Environment {
public:
  DerivedEnv(GrandParentClass* grandpaClass) : Environment() { . . . }
};
#include "GrandParentClass.h"
#include "Environment.h"

class ParentClass : public GrandParentClass {
public:
  ParentClass() {
    printf("In ParentClass constructor\n");
    m_pEnv = new DerivedEnv(this);
    m_pEnv->functionB(val);
  }
protected:
  Environment* m_pEnv;

  virtual void thisFunct() {
    printf("Calling functionB from ParentClass::thisFunct()\n");
    m_pEnv->functionB(val);
  }

};
#include "ParentClass.h"

class DerivedClass : public ParentClass {
public:
  DerivedClass() : ParentClass() {
    printf("In DerivedClass constructor\n");
    m_pEnv->functionB(val);
  }
  void thatFunct {
    printf("Calling functionB from DerivedClass::thatFunct()\n");
    m_pEnv->functionB(val);
  }
  void sim() {
    thisFunct();
    printf("Calling functionB from DerivedClass::sim()\n");
    m_pEnv->functionB(val);
  }

};
DerivedClass.h

#include "SimEnv.h"

class Environment : public SimEnv {
public:
  virtual int functionA(int arg) {
    printf("I'm in functionA\n");
    . . .
  }
  virtual int functionB(int arg) {
    printf("I'm in functionB\n");
    . . .
  }
};
#include "Environment.h"

class DerivedEnv : public Environment {
public:
  DerivedEnv(GrandParentClass* grandpaClass) : Environment() { . . . }
};
#include "GrandParentClass.h"
#include "Environment.h"

class ParentClass : public GrandParentClass {
public:
  ParentClass() {
    printf("In ParentClass constructor\n");
    m_pEnv = new DerivedEnv(this);
    m_pEnv->functionB(val);
  }
protected:
  Environment* m_pEnv;

  virtual void thisFunct() {
    printf("Calling functionB from ParentClass::thisFunct()\n");
    m_pEnv->functionB(val);
  }

};
#include "ParentClass.h"

class DerivedClass : public ParentClass {
public:
  DerivedClass() : ParentClass() {
    printf("In DerivedClass constructor\n");
    m_pEnv->functionB(val);
  }
  void thatFunct {
    printf("Calling functionB from DerivedClass::thatFunct()\n");
    m_pEnv->functionB(val);
  }
  void sim() {
    thisFunct();
    printf("Calling functionB from DerivedClass::sim()\n");
    m_pEnv->functionB(val);
  }

};
main.cc

#include "DerivedClass.h"
void main() {
  . . .
  static DerivedClass derivedClass;
  derivedClass.sim();
  . . .
}
我遇到的问题是,当我运行代码并引用DerivedClass时,我会得到以下结果:

In ParentClass constructor
I'm in functionB
In DerivedClass constructor
I'm in functionA
Calling functionB from ParentClass::thisFunct()
I'm in functionB
Calling functionB from DerivedClass::sim()
I'm in functionA
因此,我的程序在ParentClass的构造函数中调用了正确的虚函数,但随后在DerivedClass的构造函数中调用了错误的函数。这是我到目前为止检查过的:

  • 我已经确定这不是我的身材被破坏的问题
  • 我已经在父类的构造函数和派生类的构造函数中使用
    p/a(*(void***)m_pEnv)[0]@30
    打印了gdb中的vtable。两个vTable显示相同
  • 我在互联网上搜索过,似乎这类问题可能是由于堆栈损坏造成的。这是真的吗?如何调试它?这个问题还有其他解释吗

    添加 我进行了进一步调试,发现这里似乎存在上下文问题。当我从父类的任何成员函数调用functionB时,它确实正确地执行了它

    似乎只是从DerivedClass调用了错误的函数


    我修改了伪代码来强调这一点。

    您不应该从构造函数或析构函数调用虚函数。原因是派生类的对象在那一点上不完整。

    我发现了问题所在。它实际上相当平淡无奇。这是一种在不同位置具有相同文件名的文件中定义相同类的两个不同版本的情况

    我认为这是预处理器的问题。我不完全理解,但这里是我的初步解释

    我已经编辑了上面的伪代码。我的目录结构与此类似:

    include/Environment.h
    include/DerivedEnv.h
    include/Environment.h
    include/SimEnv.h
    include/ParentClass.h
    include/GrandParentClass.h
    sim/main.cc
    sim/DerivedClass.h
    ...
    distant_remote_directory/SimEnv.h -> this file slightly different from include/SimEnv.h
    
    因为远程目录位于给定给g++的include路径中,main.h从那里获取它。但是在编译ParentClass时,由于文件SimEnv.h位于同一目录中,因此它在远程目录中的文件之前被拾取。所以DerivedClass和ParentClass看到了同一个类的不同版本


    谢谢大家的帮助。

    此处不适用。在
    上没有调用这些
    。请不要忽略重要的细节,例如
    m_pEnv
    ?事实上,废话--请发布真实的、可编译的代码,而不是伪代码。否则会有太多烦恼。制作一个最小、完整的示例来展示您的问题。使用此伪代码修复所有问题后,我的版本会在两行上打印
    I'm in functionB
    。我的投票结果是“它在其他地方被破坏了”。伪代码没有显示任何类曾经引用过functionA,请在真实代码中解释functionA的完整模式。感谢您的评论。不幸的是,发布真正的代码是不切实际的。它实际上是跨越数百个文件的多线程Verilog/C++/SystemC协同模拟环境的一部分。所以很可能是“它在别的地方坏了”。我理解在没有所有信息的情况下给出建议是很困难的,我不希望得到完整的解决方案,我很乐意就如何进行调试提出建议或想法。这是我唯一一次看到编译器从一个函数转到另一个函数(不是不同的虚拟重载)在头中添加虚拟函数后,某些内容没有重新编译。我会从双重检查构建开始,即使这意味着删除所有库/对象并从头开始构建。