2008-11-21 10 views
4

Я считал, что виртуализация не работает в конструкторе суперкласса в соответствии с дизайном ООП. Например, рассмотрим следующий код C#.Виртуализация в Super Class Constructor

using System; 
namespace Problem 
{ 
    public class BaseClass 
    { 
     public BaseClass() 
     { 
      Console.WriteLine("Hello, World!"); 
      this.PrintRandom(); 
     } 
     public virtual void PrintRandom() 
     { 
      Console.WriteLine("0"); 
     } 
    } 

    public class Descendent : BaseClass 
    { 
     private Random randomValue; 
     public Descendent() 
     { 
      Console.WriteLine("Bonjour, Monde!"); 
      randomValue = new Random(); 
     } 
     public override void PrintRandom() 
     { 
      Console.WriteLine(randomValue.NextDouble().ToString()); 
     } 

     public static void Main() 
     { 
      Descendent obj = new Descendent(); 
      obj.PrintRandom(); 
      Console.ReadLine(); 
     } 
    } 
} 

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

Аналогичный код работает в C++, так как вызов PrintRandom не направляется в производном классе, так как ИМО, порядок в C++ это что-то вроде:


1. вызов для конструктора базового класса
2. Обновление V - Таблица для этого класса
3. вызова код конструктора

Мой вопрос заключается в том, что я, во-первых ли я прав, что в соответствии с принципами объектно-ориентированного программирования, виртуализация не должна/не работает в конструктор класса супер и, во-вторых, если Я прав, то почему поведение отличается на всех языках .NET (у меня есть тест ed с C#, VB.NET и MC++)

ответ

4

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

Очевидно, что, как вы можете видеть, управляемый код работает по-другому, потому что (iirc) весь объект строится до того, как вызываются конструкторы, и таким образом вы получаете виртуальную функцию подкласса перед конструктором подкласса. Это документированное различие между поведением языков, но должно быть согласованным на всех языках .NET (поскольку все они скомпилируются с одним и тем же ИЛ).

3

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

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

Что касается того, почему MC++ не работать таким образом, я не знаю - я предлагаю вам сравнить генерируемый ИЛ. Я предполагаю, что он явно вызывает вызов не виртуального метода.

РЕДАКТИРОВАТЬ: Я подозреваю, что неправильно понял вопрос - в каком направлении работает MC++? Если он работает так, как работает C#, это хорошая вещь IMO, обеспечивающая согласованное представление на платформе .NET.

0

Я бы предложил использовать FxCop для вашего кода. Я работал со многими людьми, которые отклоняют предметы, поднятые этим инструментом, как несущественные, но если ваш код содержит много мелких проблем (например, ваш), то шансы быть укушенными одним или несколькими из них намного выше.

Анализ кода ReSharper также поднимет этот вопрос.