Вызов виртуальной функции переходит в неправильную функцию, когда вызывается из конструктора производного класса, но не из родительского класса - PullRequest
0 голосов
/ 01 ноября 2011

Ниже приведена структура классов (подробности опущены).

Environment.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");
    . . .
  }
};

DerivedEnv.h

#include "Environment.h"

class DerivedEnv : public Environment {
public:
  DerivedEnv(GrandParentClass* grandpaClass) : Environment() { . . . }
};

ParentClass.h

#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);
  }

};

DerivedClass.h

#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. Это то, что я проверил до сих пор:

  1. Я убедился, что проблема не в том, что моя сборка сломана.
  2. Я распечатал vtable в gdb, используя p /a (*(void ***)m_pEnv)[0]@30 в конструкторе ParentClass и в конструкторе DerivedClass. Обе таблицы показаны одинаково

Я искал в интернете, и кажется, что такие проблемы могут быть связаны с повреждением стека. Это правда? Как я могу отладить это? Есть ли другое объяснение этой проблемы.

Добавление Я продолжил отладку и понял, что здесь есть проблема контекста. Когда я вызываю functionB из любой функции-члена ParentClass, он выполняет ее правильно.

Похоже, что именно из DerivedClass вызовы идут не в ту функцию.

Я изменил псевдокод, чтобы выделить это.

Ответы [ 2 ]

0 голосов
/ 02 ноября 2011

Я узнал, что происходит не так. Это было на самом деле довольно прозаично. Это случай, когда две разные версии одного и того же класса определены в файлах с одним и тем же именем в разных местах.

Я думаю, что это проблема препроцессора. Я не до конца понимаю, но вот мое предварительное объяснение.

Я редактировал псевдокод выше. Моя структура каталогов примерно такая:

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

Поскольку distant_remote_directory во включаемом пути, заданном для g ++, main.h берет его оттуда. Но при компиляции ParentClass, поскольку файл SimEnv.h находится в том же каталоге, он выбирается раньше, чем в distant_remote_directory. Поэтому DerivedClass и ParentClass видят разные версии одного и того же класса.

Спасибо всем за помощь.

0 голосов
/ 01 ноября 2011

Вы не должны вызывать виртуальную функцию из конструктора или деструктора.Причина в том, что объект производного класса в этот момент не завершен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...