Вызов виртуальных функций внутри конструкторов - PullRequest
211 голосов
/ 07 июня 2009

Предположим, у меня есть два класса C ++:

class A
{
public:
  A() { fn(); }

  virtual void fn() { _n = 1; }
  int getn() { return _n; }

protected:
  int _n;
};

class B : public A
{
public:
  B() : A() {}

  virtual void fn() { _n = 2; }
};

Если я напишу следующий код:

int main()
{
  B b;
  int n = b.getn();
}

Можно ожидать, что n установлено на 2.

Оказывается, n установлено в 1. Почему?

Ответы [ 13 ]

0 голосов
/ 10 ноября 2017

Сначала создается объект, а затем мы присваиваем его адрес указателям. Конструкторы вызываются во время создания объекта и используются для инициализации значения членов данных. Указатель на объект входит в сценарий после создания объекта. Поэтому C ++ не позволяет нам делать конструкторы виртуальными. Другая причина заключается в том, что нет ничего похожего на указатель на конструктор, который может указывать на виртуальный конструктор, поскольку одно из свойств виртуальной функции заключается в том, что она может использоваться только указателями.

  1. Виртуальные функции используются для динамического присвоения значения, поскольку конструкторы являются статическими, поэтому мы не можем сделать их виртуальными.
0 голосов
/ 28 октября 2013

Я не вижу важности виртуального ключевого слова здесь. b - переменная статического типа, и ее тип определяется компилятором во время компиляции. Вызовы функций не будут ссылаться на vtable. Когда b создается, вызывается конструктор его родительского класса, поэтому значение _n установлено в 1.

0 голосов
/ 07 июня 2009

Во время вызова конструктора объекта таблица указателей виртуальных функций не полностью построена. Это обычно не дает ожидаемого поведения. Вызов виртуальной функции в этой ситуации может работать, но это не гарантируется, и его следует избегать, чтобы он был переносимым и следовал стандарту C ++.

...