2016-07-29 3 views
2

Im чтение this статьи о конструкторах для C++C++ виртуальной функции в конструкторе

Мы рекомендуем вам быть осторожными при вызове виртуальной функции в конструкторах. Поскольку конструктор базового класса всегда вызывается перед конструктором производного класса, функция, которая вызывается в , базовым конструктором является версия базового класса, а не производный класс . В следующем примере построения DerivedClass вызывает реализацию BaseClass из PRINT_IT(), чтобы выполнить перед DerivedClass конструктор вызывает реализацию DerivedClass из PRINT_IT() для выполнения:

пример:

class BaseClass { 
    public: 
     BaseClass() { 
      print_it(); 
     } 
     virtual void print_it() { 
      cout << "BaseClass print_it" << endl; 
     } 
    }; 

    class DerivedClass : public BaseClass { 
    public: 
     DerivedClass() { 
      print_it(); 
     } 
     virtual void print_it() { 
      cout << "Derived Class print_it" << endl; 
     } 
    }; 

    int main() { 

     DerivedClass dc; 
    } 

Вот результат:

BaseClass print_it 
Derived Class print_it 

I tried this code and the output is as stated above. Однако я также попробовал тот же самый пример без виртуального ключевого слова:

class BaseClass { 
    public: 
     BaseClass() { 
      print_it(); 
     } 
     void print_it() { 
      cout << "BaseClass print_it" << endl; 
     } 
    }; 

    class DerivedClass : public BaseClass { 
    public: 
     DerivedClass() { 
      print_it(); 
     } 
     void print_it() { 
      cout << "Derived Class print_it" << endl; 
     } 
    }; 

    int main() { 

     DerivedClass dc; 
    } 

and got the same result.

Так в чем же разница и в чем опасность, о которой они предупреждают?

@marked в двух экземплярах:

Этот вопрос отличается как consturctors как вызвать виртуальный метод вместо одного конструктора, вызывающего виртуальный метод.

+1

Опасность: в конструкторах и деструкторах виртуальные функции не являются (виртуальными). –

+2

Не совсем правильно. Они являются виртуальными, но когда выполняется конструктор, * это экземпляр класса запущенного конструктора, а не экземпляр класса, к которому он в конечном итоге принадлежит. Итак, какой конструктор запускается, может быть неожиданным. – gnasher729

+0

@ gnasher729 Не могли бы вы объяснить, что им следовало ожидать, потому что я ожидал этого результата и не вижу опасности. Не зная, что другие ожидают, может оказаться в недоразумениях. –

ответ

7

Нет никакой разницы. В этом опасность.

Если вы не знаете, лучше, чем вы могли бы ожидать, вместо этого:

Derived Class print_it 
Derived Class print_it 

Ожидание есть, потому что, если вы звоните в virtualprint_it() из функций в Base, полиморфизм означает, что вы обычно будете получать Derived вместо этого.

Но, когда вы пишете в Base конструкторе Base части объекта находится в стадии разработки, и «динамический тип» объект незавершенного строительства по-прежнему Base, не Derived. Таким образом, вы не получаете обычного полиморфного поведения.

Статья предупреждает вас об этом факте.

+0

Важно, что «построение производной части объекта еще не началось» (когда) не «вызов функции, написанный в базовом конструкторе» (где) , Если вы пишете 'Base :: Base() {Base :: nonvirt(); } void Base :: nonvirt() {this-> virt(); } 'это также достигнет' Base :: virt() 'и более позднего вызова' nonvirt() 'после завершения строительства достигнет' Derived :: virt() '. –

Смежные вопросы