Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1] 2  Все   Вниз
  Печать  
Автор Тема: Виртуальные конструкторы  (Прочитано 46908 раз)
0 Пользователей и 12 Гостей смотрят эту тему.
Лёха
Гость
« : 07-09-2008 16:05 » 

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

В случае с деструкторами:
class A
{
public:
   A(){    cout << "A()\n";           };
   ~A(){  cout << "~A()\n";   };
};

class B : public A
{
public:
   B(){     cout << "B()\n";      };
   ~B(){   cout << "~B()\n";   };
};


int main(void)
{
   A * a = new B();
   delete a;
}

результат
 A()
 B()
 ~A()

результат если юзать virtual ~A()
 A()
 B()
 ~B()
 ~A()

В данном случае компилер предпологает что а - указывает на объект А а не на В, и без явного преобразования невозможно вызвать мембер класса В посредствам указателя а.

В случае с конструкторами (если бы можно было так):
результат бы был
 A()
 ~A()

и/или конструкция типа ((В*)а)->someMember не допускалась бы

результат если юзать виртуальный конструктор (virtual A())
 A()
 B()
 ~B()
 ~A()


Конечно всё это не имеет смысла, но вопрос в том почему стандарт не принял того, что при наследовании использовать виртуальный деструктор по умолчанию. Я просто пытаюсь понять почему конструктор не может быть виртуальным.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #1 : 07-09-2008 17:04 » 

Цитата
В данном случае компилер предпологает что а - указывает на объект А а не на В, и без явного преобразования невозможно вызвать мембер класса В посредствам указателя а.
неверное утверждение, компилятор понятия не имеет, на что указывает a. Вернее имеет - он указывает на экземпляр класса A, просто этот класс имеет таблицу виртуальных функций, которые будут вызваны из класса B, так как именно адрес такого экземпляра был присвоен указателю a


Цитата
Исходя из того что, деструкторы могут быть виртуальными, почему конструкторы не могут быть таковыми ?
видимо, в этом нет смысла, так как можно не знать, для чего вызывать ДЕСТРУКТОР, но ты всегда знаешь, экземпляр КАКОГО класа создаёшь - на стеке ли или через new. Всегда тип указан.
В общем - для начала придумай примеры использования виртуального конструктора Улыбаюсь
Записан

McZim
Команда клуба

ru
Offline Offline
Пол: Мужской
Я странный


WWW
« Ответ #2 : 07-09-2008 18:00 » 

1. Нет никакого смысла в виртуальных конструкторах.
2. оформляй свой код тегами [ code ] [ /code ]
Записан

The CBO without stats is like a morning without coffee. (c) T.Kyte.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 07-09-2008 18:54 » 

Цитата: Лёха
Я просто пытаюсь понять почему конструктор не может быть виртуальным.
Потому что конструктор создаёт объект, а в C++-образных языках имя конструктора совпадает с именем класса. Моменты создания и инициализации объекта в таких языках совпадают. Поскольку до вызова конструктора объекта ещё нет, то вызов какого-либо конструктора приводит к созданию объекта именно того класса, в котором определён конструктор.

Код: (C++)
...
class X {};
class Y: public X {};
// создали объект класса X и вызвали конструктор по умолчанию подкласса Y,
// иначе автоматически вызовется конструктор не того класса.
X x = Y();
...

Так же обстоит дело в нетипизированных языках.
Код: (Javascript)
...
// Конструктор объектов типа X.
function X() {
}

/*
 * Переменная не имеет типа, тип X имеет лишь значение перемеменной - созданный при помощи
 * конструктора объект.
 */

var x = new X();
...

А вот в том же Object Pascal, где конструктор - не более чем разновидность рядовой процедуры, дело обстоит иначе. В этом языке синтаксически различается момент создания объекта определённого типа (выделение памяти под него) и момент вызова конструктора как процедуры инициализации созданного объекта начальными значениями. Поэтому виртуальные конструкторы в Object Pascal смысл имеют.
Код: (Text) Object Pascal
...
type
  TX = class
     ...
  end;
  TY = class(TX)
     ...
  end;
var
   PX: ^TX; { объявление указателя типа TX  }
   Y: TY; { объявление переменной типа TY и создание объекта типа TY до начала выполнения кода }
begin
   PX := @Y;
   PX^.Сreate; { вызов конструктора объекта для инициализации начальными значениями }
...
Хотя обычно пользуются выражениями типа:
Код: (Text) Object Pascal
...
Y := TY.Create; { явное указание класса конструктора }
...

Цитата: McZim
1. Нет никакого смысла в виртуальных конструкторах.
Ты "в корне не прав" (c) Улыбаюсь Шаблон проектирования "фабричный метод" имеет второе название "виртуальный конструктор". Виртуальный конструктор инкапсулирует механизм создания конкретной разновидности объекта какого-либо класса, когда нам нужно абстрагироваться от этого механизма и связанного с ним разнообразния конкретных разновидностей (подклассов).
Код: (C++)
class A {};
enum Selector { SB, SC };
class B: public A {};
class C: public A {};

// Виртуальный конструктор
A *СreateA(Selector selector) {
   switch(selector) {
   case SB:
      return new B();
   case SC:
      return new C();
   default:
      return NULL;
   }
}
« Последнее редактирование: 07-09-2008 19:53 от dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
McZim
Команда клуба

ru
Offline Offline
Пол: Мужской
Я странный


WWW
« Ответ #4 : 07-09-2008 20:16 » 

Цитата
Узнав о виртуальных деструкторах, естественно спросить: "Могут ли
      конструкторы то же быть виртуальными?" Если ответить коротко - нет.
      Можно дать более длинный ответ: "Нет, но можно легко получить
      требуемый эффект".
      Конструктор не может быть виртуальным, поскольку для правильного
      построения объекта он должен знать его истинный тип. Более того,
      конструктор - не совсем обычная функция. Он может взаимодействовать
      с функциями управления памятью, что невозможно для обычных
      функций. От обычных функций-членов он отличается еще тем, что
      не вызывается для существующих объектов. Следовательно нельзя получить
      указатель на конструктор.
      Но эти ограничения можно обойти, если определить функцию,
      содержащую вызов конструктора и возвращающую построенный объект.
      Это удачно, поскольку нередко бывает нужно создать новый объект,
      не зная его истинного типа. Например, при трансляции иногда
      возникает необходимость сделать копию дерева, представляющего
      разбираемое выражение. В дереве могут быть узлы выражений разных
      видов. Допустим, что узлы, которые содержат повторяющиеся в выражении
      операции, нужно копировать только один раз. Тогда нам потребуется
      виртуальная функция размножения для узла выражения.
      Как правило "виртуальные конструкторы" являются стандартными
      конструкторами без параметров или конструкторами копирования

(c) Бьерн Страустурп.
Записан

The CBO without stats is like a morning without coffee. (c) T.Kyte.
McZim
Команда клуба

ru
Offline Offline
Пол: Мужской
Я странный


WWW
« Ответ #5 : 07-09-2008 20:18 » 

dimka, я имел ввиду что нет смысла их деражать как стандартные функции. По крайней мере для меня.
Записан

The CBO without stats is like a morning without coffee. (c) T.Kyte.
Лёха
Гость
« Ответ #6 : 08-09-2008 04:49 » 

      Конструктор не может быть виртуальным, поскольку для правильного
      построения объекта он должен знать его истинный тип.
      Вот и строил бы конструктор НЕ правильно объект, не будучи виртуальным ... или строил бы не знаючи его истиный тип )
« Последнее редактирование: 08-09-2008 05:16 от Вад » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 08-09-2008 05:01 » 

Цитата: Лёха
или строил бы не знаючи его истиный тип )
Если бы, да кабы... В C++ это не так по объяснённым выше причинам, поэтому и обсуждать тут нечего.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Лёха
Гость
« Ответ #8 : 08-09-2008 07:01 » 

интересно девки пляшут
Записан
McZim
Команда клуба

ru
Offline Offline
Пол: Мужской
Я странный


WWW
« Ответ #9 : 08-09-2008 07:06 » 

Цитата: Лёха
... или строил бы не знаючи его истиный тип )

так нельзя!

можно и нужно так
Код:
class expr {
      // ...
      public:
      expr(); // стандартный конструктор
      virtual expr* new_expr() { return new expr(); } //не стандартный конструктор
      };

      Виртуальная функция new_expr() просто возвращает стандартно
      инициализированный объект типа expr, размещенный в свободной памяти.
Записан

The CBO without stats is like a morning without coffee. (c) T.Kyte.
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #10 : 08-09-2008 07:11 » 

Зайдём с другой стороны Улыбаюсь

Код:
class A 
{
public:
    A(){}
}

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

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

и как прикажешь компилятору понимать, что создавать в конструкции
Код:
A var;
A* pVar = new A();
если у тебя конструктор "виртуальный"? A, B, или, может, C? Будет создаваться A. И точка. Ибо компилятор телепатическими способностями не наделён Улыбаюсь
Записан
sss
Специалист

ru
Offline Offline

« Ответ #11 : 08-09-2008 08:03 » 

Блин, тема нонсенс для типизированных языков.
Записан

while (8==8)
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #12 : 08-09-2008 09:02 » 

Цитата
и как прикажешь компилятору понимать, что создавать в конструкции
Код:

A var;
A* pVar = new A();
не, пример неубедительный Улыбаюсь Будет создаваться A , даже если "конструктор виртуальный"
Записан

Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #13 : 08-09-2008 09:46 » 

Цитата: sss
Блин, тема нонсенс для типизированных языков.
Почему это? Для типизированного Object Pascal совсем не "нонсенс", но "нонсенс" для нетипизированного JavaScript.

Цитата: Вад
Будет создаваться A.
Цитата: Алексей1153++
Будет создаваться A , даже если "конструктор виртуальный"
В метафизическом смысле B и C - это тоже A. Поэтому, хотя вы и правы, но это ничего не объясняет Улыбаюсь А как тут сказать коротко, но ёмко, я ещё не придумал. Улыбаюсь
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #14 : 08-09-2008 12:06 » 

Лёха, Компилятор С++ долго не думает. Если есть двойственность построения участка кода, он просто отсылает "привет" в консоль. Чтобы программист сам определился, чего он хочет. При этом этот участок пропускается и объектный файл не строится. По названным dimka причинам, громоздить виртуальные конструкторы в С++ не имеет смысла. При написании кода, ты явно знаеш, какой именно класс будет использоваться, и соответственно его создаеш.
В С++ есть недочеты и сложности. Но это не один из них.
« Последнее редактирование: 08-09-2008 12:13 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #15 : 08-09-2008 13:45 » 

"Ну я на вас просто удивляюсь" (с)

Все согласны, что тема не имеет смысла, но продолжаете обсуждать. Блин, мне бы столько времени.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
sss
Специалист

ru
Offline Offline

« Ответ #16 : 09-09-2008 00:56 » 

dimka, что это за виртуальный конструктор в Object Pascal? Он виртуален только тем, что может указывать цепь конструкторов?
Код:
  type A = class
    constructor LoadFrom( filename: String); virtual;
  end;

  type B = class ( A)
    constructor LoadFrom( filename: String); virtual;
  end;

  class A
  {
     A( char* filename);
  }

  class B : A
  {
     B( char* filename) : A( filename) {};  // <= Виртуальный как в ObjectPascal ???
  }

Какая вообще виртуальность в JavaScript? Может быть не виртуальность, а использование VARIANT?

Записан

while (8==8)
zubr
Гость
« Ответ #17 : 09-09-2008 04:44 » 

Хмм... В ObjectPascal виртуальный конструктор также бессмыслен. Насколько я помню теорию, таблица виртуальных методов в ObjectPascal создается в конструкторе, поэтому бессмысленно делать конструктор виртуальным. Кстати код:
Цитата
Код: (Object Pascal)

...
type
  TX = class
     ...
  end;
  TY = class(TX)
     ...
  end;
var
   PX: ^TX; { объявление указателя типа TX  }
   Y: TY; { объявление переменной типа TY и создание объекта типа TY до начала выполнения кода }
begin
   PX := @Y;
   PX^.Сreate; { вызов конструктора объекта для инициализации начальными значениями }
...
не прокатит, будет аксесс виолейшн, так как объект Y не инициализирован. Тогда надо будет вызывать конструктор Y:
Код:
PX := @Y;
Y:=TY.Create;// или Y:=TX.Create;
PX^.Сreate;
Но тогда пропадает смысл виртуального конструктора.
Записан
sss
Специалист

ru
Offline Offline

« Ответ #18 : 09-09-2008 05:26 » 

zubr, в CBuilder ( не уверен за VC) в конструкторе вообще нельзя вызывать виртуальные методы

Код:
  class A
  {
     A() { func();};
    virtual void func() { printf( "A::func");};
  }

  class B : A
  {
     B():A(){ };
    virtual void func() { printf( "B::func");};
  }

  void main()
  {
     B b;
  }

Напечатает A::func. Отсюда можно сделать вывод, что перезапись таблицы на очередном уровне полиморфизма производится перед вызовом конструктора текущего в иерархии потомка.
Возможно, и скорее всего, слово virtual для конструкторов в ObjectPascal указывает компилятору, что конструктор должен быть вызван после полного заполнения VTM на всех уровнях иерархии.
Записан

while (8==8)
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #19 : 09-09-2008 07:06 » 

Цитата: sss
что это за виртуальный конструктор в Object Pascal? Он виртуален только тем, что может указывать цепь конструкторов?
Нет.

Цитата: zubr
не прокатит, будет аксесс виолейшн, так как объект Y не инициализирован.
Вполне возможно, мне не на чем проверить.

Цитата: zubr
Насколько я помню теорию, таблица виртуальных методов в ObjectPascal создается в конструкторе, поэтому бессмысленно делать конструктор виртуальным.
Тем не менее, они есть.

Здесь приводится пример использования виртуальных конструкторов через метакласс в Object Pascal.
http://www.rsdn.ru/article/Delphi/delphiabs.xml
Здесь конкретный класс передаётся как экземпляр метакласса и определяется не во время компиляции, а во время исполнения, и вызов конструктора объекта есть вызов виртуального метода у экземпляра метакласса, коим этот конструктор и является. Моё объяснение выше про разделение времени создания и инициализации объекта было неправильным.

На самом деле, если бы в Object Pascal существовал бы более внятный механизм reflections, то писать "virtual" у конструктора не пришлось бы. Здесь же получается, что метаклассы упорядочены в такую же иерархию, как и их классы - только в этом смысле оправдана виртуальность конструктора.

Цитата: sss
Какая вообще виртуальность в JavaScript?
Выражение "виртуальный метод" имеет смысл лишь в ряде языков, например, в C++. Но наличие таких методов означает включение полиморфизма поведения объекта во время исполнения. В таких языках, как JavaScript, полиморфизм поведения объектов существует всегда и не отключается, поэтому выражение "виртуальный метод" для таких языков большого смысла не имеет. Но, поскольку мы тут общаемся на территории C++-ников, то не вижу ничего плохого в том, чтобы, для большей им понятности, говорить про "виртуальные методы" в том числе и в JavaScript, полагая, что в JavaScript все методы всегда "виртуальны".

И вообще я про "виртуальность" в JavaScript не говорил, я говорил о том, что "виртуальные конструкторы" в JavaScript не могут существовать на уровне синтаксиса этого языка, поскольку моменты создания и инициализации объекта неразделимы.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #20 : 09-09-2008 07:11 » 

Цитата: sss
в CBuilder ( не уверен за VC) в конструкторе вообще нельзя вызывать виртуальные методы
Насколько я понимаю, применительно к C++ из конструктора вызов виртуальных методов бессмысленен, поскольку конструктор предка выполняется ещё до выполнения конструктора потомка, и в момент работы конструктора предка виртуальные методы потомка просто ещё не определены. Хотя, быть может, это и не так - иначе будут проблемы с абстрактными методами. Но если это не так, то будут проблемы при работе самих виртуальных методов, поскольку они относятся к коду потомка, а объект как объект класса потомка ещё не определён - атрибуты потомка ещё не инициализированы.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
sss
Специалист

ru
Offline Offline

« Ответ #21 : 09-09-2008 07:23 » 

dimka, так зачем тогда слово virtual в ObjectPascal для constructor? Зачем было вообще в тему ANSI С++ замешивать ObjectPascal, который до компиляции выполняет над иерархиями классов дополнительную, работу  "являющуюся деталью реализации, скрытой от программиста"?

Квадратура круга forever..
« Последнее редактирование: 09-09-2008 07:25 от sss » Записан

while (8==8)
Лёха
Гость
« Ответ #22 : 09-09-2008 07:33 » 

McZim привел хороший пример
Код:
class expr {
      // ...
      public:
      expr(); // стандартный конструктор
      virtual expr* new_expr() { return new expr(); } //не стандартный конструктор
      };

       Сдесь на этапе компиляции не известно объект какого типа будет создаваться. Возможно я хотел что бы именно виртуальный конструктор заменял примеры подобного рода.
Товарищи ... кинте ссыллок, кто сколько сможет ) на статьи по поводу виртуальных функций, VTBL, хочеццо  подробнее узнать про тайну третьей планеты )
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #23 : 09-09-2008 07:49 » 

Цитата
Сдесь на этапе компиляции не известно объект какого типа будет создаваться
expr и будет создаваться )
Записан

Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #24 : 09-09-2008 08:12 » 

Цитата: sss
Зачем было вообще в тему ANSI С++ замешивать ObjectPascal, который до компиляции выполняет над иерархиями классов дополнительную, работу  "являющуюся деталью реализации, скрытой от программиста"?
Для общего развития. Автор темы заявил, что пытается понять, почему конструктор не может быть виртуальным. И ему тут объясняют, почему не может именно в C++ - для этого нужен Object Pascal Ага.

И о какой же "скрытой от программиста" реализации идёт речь, если программист явно программирует эту "дополнительную работу над иерархиями классов"?
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
sss
Специалист

ru
Offline Offline

« Ответ #25 : 09-09-2008 08:39 » 

Так это же цитата из статьи http://www.rsdn.ru/article/Delphi/delphiabs.xml  Ага
Записан

while (8==8)
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #26 : 09-09-2008 13:02 » 

sss, и что? Статья - не откровение. Не надо литературные приёмы автора буквально принимать на веру. Улыбаюсь А вот в виртуальные конструкторы верить не нужно - нужно лишь проверить в Delphi или Free Pascal Улыбаюсь
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #27 : 09-09-2008 13:33 » 

Цитата
Сдесь на этапе компиляции не известно объект какого типа будет создаваться
expr и будет создаваться )
Метод виртуальный - в классе-потомке может быть создан другой объект. Правильнее сказать, что вызывающая метод программа не может знать, указатель на объект какого типа вернется (но точно известно, что или expr, или его потомки).
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
sss
Специалист

ru
Offline Offline

« Ответ #28 : 10-09-2008 01:38 » 

dimka, так что же все таки обозначает virtual constructor в ObjectPascal? Интересно. Я как раз не только не верю в виртуальные конструкторы, но и вообще все время пытаюсь доказать об несуществующем термине. Я так понимаю: в ObjectPascal вызов виртуального конструктора вначале выделяет память под объект класса, заполняет всю связанную с классом информацию (RTTI, VTM), а затем просто вызывает метод, обрамленный в определении класса как virtual constructor.
Записан

while (8==8)
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #29 : 10-09-2008 03:39 » new

Цитата: sss
Я как раз не только не верю в виртуальные конструкторы, но и вообще все время пытаюсь доказать об несуществующем термине.
Вот доказывать несуществование термина, когда термин употребляется в Object Pascal и в шаблонах проектирования - занятие бессмысленное. Нужно разобраться в том, какой смысл вкладывают авторы в этот термин.

Тут нечего доказывать, но можно спорить с авторами о том, что они выбрали неудачный термин.

Это уже несколько выходит за рамки раздела о C++ и подходит для раздела о Delphi, но всё же:
Цитата: sss
Я так понимаю: в ObjectPascal вызов виртуального конструктора вначале выделяет память под объект класса, заполняет всю связанную с классом информацию (RTTI, VTM), а затем просто вызывает метод, обрамленный в определении класса как virtual constructor.
Ты понимаешь, что такое метакласс? Для чего появились метаклассы сперва в Smalltalk, а потом расползлись по другим языкам?
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Страниц: [1] 2  Все   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines