2015-11-12 3 views
4

В следующем примере кода milk инициализируется конструктором, а egg - нет. milk.spill() не segfault, но egg.crack(). В чем разница между двумя способами инициализации переменной экземпляра? Почему первое правильное, в то время как последнее вызывает segfaults?В чем разница между инициализацией переменных экземпляра в & из конструктора?

import std.stdio; 

void main() { 
    auto k = new Kitchen(); 
    k.pollute(); 
} 

class Kitchen { 
    Milk milk; 
    Egg egg = new Egg(); 

    this() { 
    milk = new Milk(); 
    } 

    void pollute() { 
    writeln("spilling milk"); 
    milk.spill(); 
    writeln("cracking egg"); 
    egg.crack(); 
    } 
} 

class Milk { 
    bool spilt = false; 
    void spill() { spilt = true; } 
} 

class Egg { 
    bool cracked = false; 
    void crack() { cracked = true; } 
} 
+0

Вы уверены, что предоставили вам правильный пример? Оно работает. Возможно, вы хотели удалить часть «= new Egg();»? –

+0

egg.crack не должен был там преградить, и не для меня. Есть разница между двумя строками, важное отличие, которое смущает людей, и я могу это записать, но ваш примерный код работает для меня. Это для вас тоже непоправимо или это отрывок из более крупной вещи? –

+0

У меня когда-то была эта проблема. Как сообщество объясняло мне все это: http://forum.dlang.org/post/[email protected] – sigod

ответ

5

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

В этом примере это означает, что для каждого объекта Kitchen создан новый объект Milk. Когда вы запустите new Kitchen, запустится конструктор, то есть вы получите new Milk.

Egg - другой. Он находится в статическом контексте, так что инициализатор запускается во время компиляции - только один раз. Это означает, что существует только одинEgg поделился среди всех new Kitchen s. Сама переменная не является статической, если вы назначили ее new Egg после создания new Kitchen, это повлияло бы только на экземпляр кухни, но объект, к которому он относится сразу , является.

Так что, если вы просто установите его на new Egg вне конструктора и не замените его, любые изменения, которые вы сделаете с этим яйцом, будут видны во всех экземплярах кухни - после того, как вы взломаете яйцо, затем сделайте еще new Kitchen, это будет уже есть потрескавшееся яйцо!