Re[3]: Virtual member call in constructor. Плохо?
От: Sinclair Россия https://github.com/evilguest/
Дата: 02.11.07 12:17
Оценка: 11 (3) +1
Здравствуйте, igna, Вы писали:
I>А польза какая от решения принятого в C#, ну то есть от того, что конструктор базового класса вызывает виртуальную функцию производного класса?
Никакой специальной пользы нет, как и вреда.
Просто другая архитектура. Тип объекта никогда не меняется в течение его жизни. А в С++ объект при создании/разрушении проходит всю эволюционную цепочку. В управляемой среде так делать просто нельзя — например, если в конструкторе какого-либо из классов в цепочке наследования произойдет исключение, тип объекта должен быть правильным.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Virtual member call in constructor. Плохо?
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 30.10.07 14:34
Оценка: 10 (2) +1
Здравствуйте, <Аноним>, Вы писали:

А>Может и простенький вопрос, но мне не понятно:

А>чем плох вызов виртуального метода из конструктора?
Эта проблема называется "потерей указателя this". В наследнике переопределенный метод может обратиться к полю класса (this.*), считая, что совершает вполне легальное действие, в то время как конструктор, быть может, еще не успел инициализировать данное поле (в зависимости от кода конструктора) — и вылетит исключение обращения по пустой ссылке, к примеру. В общем случае конструктор не должен "терять this" (делать его доступным кому-либо) вплоть до своего завершения.
Re[2]: Virtual member call in constructor. Плохо?
От: Mab Россия http://shade.msu.ru/~mab
Дата: 30.10.07 14:51
Оценка: +2
Здравствуйте, denezuela, Вы писали:

D>по крайней мере так дело обстоит с С++.

В .NET CLR оно обстоит иначе.
Re[9]: Virtual member call in constructor. Плохо?
От: Mab Россия http://shade.msu.ru/~mab
Дата: 06.11.07 10:16
Оценка: 8 (1)
Здравствуйте, rsn81, Вы писали:

Да. Будет
.method public hidebysig specialname rtspecialname 
        instance void  .ctor() cil managed
{
  // Code size       21 (0x15)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  call       instance void A::.ctor()
  IL_0006:  nop
  IL_0007:  nop
  IL_0008:  ldarg.0
  IL_0009:  newobj     instance void [mscorlib]System.Object::.ctor()
  IL_000e:  stfld      object B::obj
  IL_0013:  nop
  IL_0014:  ret
} // end of method B::.ctor

и
.method public hidebysig specialname rtspecialname 
        instance void  .ctor() cil managed
{
  // Code size       21 (0x15)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  newobj     instance void [mscorlib]System.Object::.ctor()
  IL_0006:  stfld      object B::obj
  IL_000b:  ldarg.0
  IL_000c:  call       instance void A::.ctor()
  IL_0011:  nop
  IL_0012:  nop
  IL_0013:  nop
  IL_0014:  ret
} // end of method B::.ctor

соответственно.
Re[4]: Virtual member call in constructor. Плохо?
От: Mab Россия http://shade.msu.ru/~mab
Дата: 30.10.07 15:04
Оценка: 6 (1)
Здравствуйте, Аноним, Вы писали:
А>А разве инициализация полей дефолтовыми значениями происходит не до выполнения конструктора?
Происходит. Вопрос не этом, а в том, что возможна производному классу нужна более сложная инициализация, которую выполняет еще не вызванный конструктор.
Re[2]: Virtual member call in constructor. Плохо?
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 30.10.07 14:47
Оценка: 2 (1)
Все гадости, которые только можно совершить в конструкторе, описаны в статье Теория и практика Java: Методы безопасного конструирования. Не позволяйте указателю "this" пропадать во время конструирования — .NET/Java не принципиально.
Re[6]: Virtual member call in constructor. Плохо?
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 30.10.07 15:20
Оценка: 1 (1)
Здравствуйте, vladpol, Вы писали:

V>Можно ли тогда сказать, что вызов виртальных методов в конструкторе, не есть плохо, но к этому надо подходить внимательно?

Это есть плохо и надо выжигать каленым железом. Сколь ни подходи внимательно, если указатель this опубликован, то... кто-нибудь да когда-нибудь его попытается дернуть раньше времени. И это может сделать вовсе не сам внимательный автор класса, не сам внимательный автор всей библиотеки, не самый внимательнейший автор движка или системы — а кто-то, кто не знает, о том что все они (а кое-то из них по-дурости совершенно сознательно), даже будучи внимательными, заложили в свою систему риск безопасности инициализации.
Это как ружье, что висит на стене в первом акте спектакля...
Re[7]: Virtual member call in constructor. Плохо?
От: Mab Россия http://shade.msu.ru/~mab
Дата: 06.11.07 09:57
Оценка: +1
Здравствуйте, rsn81, Вы писали:

В .NET код, инициализирующий члены, вставляется до вызова конструктора базового класса.
Virtual member call in constructor. Плохо?
От: Аноним  
Дата: 30.10.07 14:25
Оценка:
Привет всем.

Может и простенький вопрос, но мне не понятно:
чем плох вызов виртуального метода из конструктора?

Спасибки
Re: Virtual member call in constructor. Плохо?
От: denezuela Россия  
Дата: 30.10.07 14:39
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Привет всем.


А>Может и простенький вопрос, но мне не понятно:

А>чем плох вызов виртуального метода из конструктора?

А>Спасибки


Скорее всего, дело в том, что пока не выполнились все конструкторы, объект полностью не сконструирован, а следовательно таблица виртуальных функций (или что там в net framework) не полностью загружена в память, и виртуальность не может быть корректно разрешена, по крайней мере так дело обстоит с С++.
Re[3]: Virtual member call in constructor. Плохо?
От: Аноним  
Дата: 30.10.07 14:50
Оценка:
Здравствуйте, rsn81, Вы писали:

R>Все гадости, которые только можно совершить в конструкторе, описаны в статье Теория и практика Java: Методы безопасного конструирования. Не позволяйте указателю "this" пропадать во время конструирования — .NET/Java не принципиально.


Спасибо. Полезная для меня инфа.
Re[2]: Virtual member call in constructor. Плохо?
От: _FRED_ Черногория
Дата: 30.10.07 14:52
Оценка:
Здравствуйте, denezuela, Вы писали:

А>>Может и простенький вопрос, но мне не понятно:

А>>чем плох вызов виртуального метода из конструктора?

D>Скорее всего, дело в том, что пока не выполнились все конструкторы, объект полностью не сконструирован, а следовательно таблица виртуальных функций (или что там в net framework) не полностью загружена в память, и виртуальность не может быть корректно разрешена, по крайней мере так дело обстоит с С++.


Здесь не так Тут именно что поля могут быть ещё непроинициализированы.
Help will always be given at Hogwarts to those who ask for it.
Re[3]: Virtual member call in constructor. Плохо?
От: Аноним  
Дата: 30.10.07 15:02
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здесь не так Тут именно что поля могут быть ещё непроинициализированы.


А разве инициализация полей дефолтовыми значениями происходит не до выполнения конструктора?
Re[3]: Virtual member call in constructor. Плохо?
От: Аноним  
Дата: 30.10.07 15:08
Оценка:
Здравствуйте, rsn81, Вы писали:

R>Все гадости, которые только можно совершить в конструкторе, описаны в статье Теория и практика Java: Методы безопасного конструирования. Не позволяйте указателю "this" пропадать во время конструирования — .NET/Java не принципиально.


Исходя из статьи следует, что проблемы могут возникнуть только при многопоточности.
Я уже понял, что это плохая практика, но всё же интересно: однопоточному приложению это ничем не грозит?
Re[5]: Virtual member call in constructor. Плохо?
От: vladpol Украина http://vlad-mislitel.livejournal.com/
Дата: 30.10.07 15:09
Оценка:
Здравствуйте, Mab, Вы писали:

Mab>Здравствуйте, Аноним, Вы писали:

А>>А разве инициализация полей дефолтовыми значениями происходит не до выполнения конструктора?
Mab>Происходит. Вопрос не этом, а в том, что возможна производному классу нужна более сложная инициализация, которую выполняет еще не вызванный конструктор.
Можно ли тогда сказать, что вызов виртальных методов в конструкторе, не есть плохо, но к этому надо подходить внимательно?
С уважением, Владислав Полищук
Re[4]: Virtual member call in constructor. Плохо?
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 30.10.07 15:12
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Исходя из статьи следует, что проблемы могут возникнуть только при многопоточности.

Не следует, прочитайте внимательнее.

А>Я уже понял, что это плохая практика, но всё же интересно: однопоточному приложению это ничем не грозит?

Грозит.
Re[6]: Virtual member call in constructor. Плохо?
От: _FRED_ Черногория
Дата: 30.10.07 15:18
Оценка:
Здравствуйте, vladpol, Вы писали:

V>Можно ли тогда сказать, что вызов виртальных методов в конструкторе, не есть плохо,


Имхо, есть, но этого часто попросту не избежать (изменение свойства "Property" формы в InitializeComponent часто приводит к вызову виртуального метода "OnPropertyChanged" :о()

V>но к этому надо подходить внимательно?


Да
Help will always be given at Hogwarts to those who ask for it.
Re[6]: Virtual member call in constructor. Плохо?
От: Mab Россия http://shade.msu.ru/~mab
Дата: 30.10.07 15:18
Оценка:
Здравствуйте, vladpol, Вы писали:

V>Можно ли тогда сказать, что вызов виртальных методов в конструкторе, не есть плохо, но к этому надо подходить внимательно?

ИМХО да.
Re[4]: Virtual member call in constructor. Плохо?
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 30.10.07 15:20
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>А разве инициализация полей дефолтовыми значениями происходит не до выполнения конструктора?

Не до завершения родительского конструктора.
Re[6]: Virtual member call in constructor. Плохо?
От: _FRED_ Черногория
Дата: 30.10.07 15:27
Оценка:
Здравствуйте, vladpol, Вы писали:

V>…но к этому надо подходить внимательно?


Гхм… А к чему можно подходить "не внимательно"? Просто, про это надо держать в голове, как и сотню других мелочей…
Help will always be given at Hogwarts to those who ask for it.
Re: Virtual member call in constructor. Плохо?
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.10.07 15:31
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Может и простенький вопрос, но мне не понятно:

А>чем плох вызов виртуального метода из конструктора?

Do not call overridable methods in constructors
Re[2]: Virtual member call in constructor. Плохо?
От: _FRED_ Черногория
Дата: 30.10.07 15:51
Оценка:
Здравствуйте, nikov, Вы писали:

А>>Может и простенький вопрос, но мне не понятно:

А>>чем плох вызов виртуального метода из конструктора?

N>Do not call overridable methods in constructors


Толку от этого — чуть, часто проблемы это вызывает именно во всяких "компонентах", свойства которых любят отправлять события об их, свойств, изменении, а в производных классах свойства меняются и события "отлавливаются"
Help will always be given at Hogwarts to those who ask for it.
Re: Virtual member call in constructor. Плохо?
От: vdimas Россия  
Дата: 02.11.07 11:16
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Привет всем.


А>Может и простенький вопрос, но мне не понятно:

А>чем плох вызов виртуального метода из конструктора?

Плох тем, что класс-наследник может обратиться к чему угодно в этом переопределённом методе, в т.ч. к своим еще непроинициализированным полям.

Тем не менее, дизайнеры форм и компонентов генерят метод InitializeComponent, который вызывается из конструктора, и который, в свою очередь, вызывает тонны виртуальных методов или обращается к виртуальным св-вам. Об этом надо помнить, при переопределении виртуальных св-в у Control и его наследников. Иногда я прибегаю к услугам ISupportInitialize, как к более общему решению (которое накрывает и эту проблему в т.ч.)
Re[2]: Virtual member call in constructor. Плохо?
От: igna Россия  
Дата: 02.11.07 11:37
Оценка:
Здравствуйте, nikov, Вы писали:

N>Do not call overridable methods in constructors


Значит прав был Страуструп. В C++ при выполнении конструктора базового класса вызывается виртуальная функция базового класса.

А польза какая от решения принятого в C#, ну то есть от того, что конструктор базового класса вызывает виртуальную функцию производного класса?
Re[3]: Virtual member call in constructor. Плохо?
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 02.11.07 11:51
Оценка:
Здравствуйте, igna, Вы писали:

Здесь Re: Virtual member call in constructor. Плохо?
Автор: denezuela
Дата: 30.10.07
и ниже.
Re[4]: Virtual member call in constructor. Плохо?
От: igna Россия  
Дата: 02.11.07 12:22
Оценка:
Здравствуйте, rsn81, Вы писали:

R>Здесь Re: Virtual member call in constructor. Плохо?
Автор: denezuela
Дата: 30.10.07
и ниже.


Там написано "...виртуальность не может быть корректно разрешена, по крайней мере так дело обстоит с С++", а это неверно. В C++ виртуальность разрешается в пользу функции базового класса.
Re[5]: Virtual member call in constructor. Плохо?
От: Mab Россия http://shade.msu.ru/~mab
Дата: 02.11.07 12:36
Оценка:
Здравствуйте, igna, Вы писали:


I>Там написано "...виртуальность не может быть корректно разрешена, по крайней мере так дело обстоит с С++", а это неверно. В C++ виртуальность разрешается в пользу функции базового класса.

Ну вот с точки зрения .NET это некорректное поведение
Re[6]: Virtual member call in constructor. Плохо?
От: igna Россия  
Дата: 02.11.07 12:47
Оценка:
Здравствуйте, Mab, Вы писали:

Mab>Ну вот с точки зрения .NET это некорректное поведение


Ну да. А корректное с точки зрения .NET поведение приводит к появлению советов вроде "Do not call overridable methods in constructors".
Re[7]: Virtual member call in constructor. Плохо?
От: Sinclair Россия https://github.com/evilguest/
Дата: 06.11.07 05:58
Оценка:
Здравствуйте, igna, Вы писали:
I>Ну да. А корректное с точки зрения .NET поведение приводит к появлению советов вроде "Do not call overridable methods in constructors".
Позволю себе напомнить, что вызов виртуальных методов из конструкторов в C++ также является порочной практикой.
И ровно по той причине, что виртуальность работает не так, как в других методах. Так что хрен редьки не слаще.
Классической задачкой на понимание неочевидностей процесса конструирования объекта в C++ является вопрос "можно ли произвести вызов абстрактного метода без хаков с кастом?".
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Virtual member call in constructor. Плохо?
От: vensub Украина  
Дата: 06.11.07 08:42
Оценка:
Здравствуйте, rsn81, Вы писали:

R>Здравствуйте, <Аноним>, Вы писали:


А>>А разве инициализация полей дефолтовыми значениями происходит не до выполнения конструктора?

R>Не до завершения родительского конструктора.

след. пример показывает, что вы ошибаетесь:

class Program
{
static void Main(string[] args) {
new Derived();
Console.ReadLine();
}
}

class Base
{
public Base() {
Console.WriteLine(string.Format("i = {0}", this.GetType().GetField("i").GetValue(this)));

Console.WriteLine("Base .ctor end");
}
}
class Derived : Base
{
public int i = 3;

public Derived() {
Console.WriteLine(string.Format("i = {0}", i));
Console.WriteLine("Derived .ctor");
}
}
Re[6]: Virtual member call in constructor. Плохо?
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 06.11.07 09:54
Оценка:
Здравствуйте, vensub, Вы писали:

V>след. пример показывает, что вы ошибаетесь:

[skipped]
Интересно. Гм... и странно, если ничего не напутали. Под рукой студии нет, проверил тоже самое в Java:
package ru.rsdn.init;

public class Base {
    public Base() {
        try {
            System.out.println("base.ctor: " +
                    getClass().getField("i").getInt(this));
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

package ru.rsdn.init;

public class Derived extends Base {
    public final int i = 1;

    public Derived() {
        System.out.println("derived.ctor: " + i);
    }

    public static void main(String... args) {
        new Derived();
    }
}
Получил в консоли:

base.ctor: 0
derived.ctor: 1

Re[8]: Virtual member call in constructor. Плохо?
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 06.11.07 10:12
Оценка:
Здравствуйте, Mab, Вы писали:

Mab>В .NET код, инициализирующий члены, вставляется до вызова конструктора базового класса.

То есть это:
class A {
    public A() {
    }
}

class B: A {
    private readonly object obj = new object();
    
    public B() {
    }
}
сгенерируется в иной MSIL-код, нежели вот это
class B: A {
    private readonly object obj;
    
    public A() {
        obj = new object();
    }
}
?
Re[10]: Virtual member call in constructor. Плохо?
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 06.11.07 10:25
Оценка:
Здравствуйте, Mab, Вы писали:

Забавно.
Интересно, ведь получается, что в .NET таким образом автоматически частично решается обсуждаемая в теме проблема...
Re[11]: Virtual member call in constructor. Плохо?
От: Mab Россия http://shade.msu.ru/~mab
Дата: 06.11.07 10:29
Оценка:
Здравствуйте, rsn81, Вы писали:

R>Интересно, ведь получается, что в .NET таким образом автоматически частично решается обсуждаемая в теме проблема...

Частично -- да, если инициализация производного класса совсем простая. Но одновременно добавляется тонкий аспект поведения, о котором нужно помнить.
Re[12]: Virtual member call in constructor. Плохо?
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 14.11.07 09:52
Оценка:
Здравствуйте, Mab, Вы писали:

Mab>Частично -- да, если инициализация производного класса совсем простая. Но одновременно добавляется тонкий аспект поведения, о котором нужно помнить.

Смотрю сейчас язык Scala под JVM. Вот такой класс:
package ru.rsdn;

class MyClass[P](property: P) {
  def getProperty() = property
}
компилируется в такой вот байт-код:
// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://kpdus.tripod.com/jad.html
// Decompiler options: packimports(3) braces deadcode fieldsfirst splitstr(80) nonlb space lnc 
// Source File Name:   MyClass.scala

package ru.rsdn;

import scala.ScalaObject;

public class MyClass implements ScalaObject {
    private Object property;

    public MyClass(Object property) {
        this.property = property;
        super();
    }

    public Object getProperty() {
        return property;
    }

    public int $tag() {
        return scala.ScalaObject.class.$tag(this);
    }
}
Смотрю внимательно на конструктор и думаю, почему все понимают суть проблемы, а Sun — нет?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.