Здравствуйте, LCR, Вы писали:
LCR>Здравствуйте, MaximE, Вы писали:
ME>>Как раз для этой цели используют идиому double dispatch.
LCR>MaximE, можно по-подробнее. Что это за идиома?
Паттерн visitor использует идиому double dispatch:
Здравствуйте, Vi2, Вы писали:
Vi2>Выбор адреса функции и вызов функции с дополнительным параметром — это изначально разные вещи. Можно выбрать функцию из vtable, но не передавать туда this.
Полностью согласен.
Vi2>Смысл? Не знаю.
С твоего позволения приведу первый пришедший в голову примерчик, который демонстрирует удобство static virtual. Допустим мы хотим иметь возможность запрашивать текстовую строку — имя класса:
1. динамически — у экземпляра
2. статически — у класса (например где-нибудь в шаблонных глубинах экземпляр недоступен, но известен класс, специализирующий этот шаблон)
Динамический вызов: pObj->typeName(). При этом методу передается this, который ему совершенно не нужен.
Статический вызов в глубинах шаблона: typename T::typeNameStatic()
Указатель на typeName() присутствует в таблице виртуальных функций, поэтому можем вызывать так: pObj->typeName()
И в то же время поскольку этой функции не передается неявный параметр this, то где-нибудь в шаблоне можем написать так: typename T::typeName()
Перечитал и понял что могут не так понять. typename T::typeNameStatic() — так в коде писать не надо, это я так подчеркивал что T не абы что, а тип специализирующий шаблон.
[]
Vi2>Так они и так так вызываются. Просто не реализовано и запрещено.
Все-таки я не пойму в чем смысл виртуальности статической функции? Объясни?
У них разная семантика. Это примерно, как: "А почему бы на свой рабочий стол не положить колесо от Камаза?".
Ты говоришь, что можно. Я спрашиваю — зачем?
Здравствуйте, folk, Вы писали:
F>Здравствуйте, Vi2, Вы писали:
Vi2>>Выбор адреса функции и вызов функции с дополнительным параметром — это изначально разные вещи. Можно выбрать функцию из vtable, но не передавать туда this.
F>Полностью согласен.
Vi2>>Смысл? Не знаю.
F>С твоего позволения приведу первый пришедший в голову примерчик, который демонстрирует удобство static virtual. Допустим мы хотим иметь возможность запрашивать текстовую строку — имя класса:
примерчик скипнут
Будешь смеяться, но твой пример -- единственная ситуация, когда мне нужны были статичекме виртульные ф-ции. Я не видел ни одной другой задачи, для которой они бы были нужны. Если у тебя были другие задачи, где применение функций статик-виртуал было бы целесообразно -- плз, приведи пример.
_>Будешь смеяться, но твой пример -- единственная ситуация, когда мне нужны были статичекме виртульные ф-ции. Я не видел ни одной другой задачи, для которой они бы были нужны. Если у тебя были другие задачи, где применение функций статик-виртуал было бы целесообразно -- плз, приведи пример.
Пожалуйста!
struct Abstract
{
static virtual Abstract* create() = 0;
};
struct Foo : public Abstract
{
static virtual Abstract* create() {return new Foo();}
};
struct Bar : public Abstract
{
static virtual Abstract* create() {return new Bar();}
};
Надо отметить, что так называемые виртуальные конструкторы в Borland C++ есть по смыслу ни что иное как такие вот статические виртуальные функции (синтаксис, конечно другой).
Можно ли без этого обойтись? Конечно можно! Для этого придумали такой паттерн как абстрактная фабрика. (В принципе, можно даже программировать в терминах машин Тьюринга, где нет ни классов, ни методов, а только лента, входные данные и текущее состояние.)
Нарушает ли "статическая виртуальность" концептуальную целостность языка? Полагаю, что нет. Я по крайней мере сложностей в реализации не вижу. И не вижу каких-либо подводных камней связанных с использованием этой фичи.
[]
Д>Надо отметить, что так называемые виртуальные конструкторы в Borland C++ есть по смыслу ни что иное как такие вот статические виртуальные функции (синтаксис, конечно другой).
А вот ты убери virtual! Получиться тоже самое.
Д>Можно ли без этого обойтись? Конечно можно! Для этого придумали такой паттерн как абстрактная фабрика. (В принципе, можно даже программировать в терминах машин Тьюринга, где нет ни классов, ни методов, а только лента, входные данные и текущее состояние.)
Ну это ты загнул! Ты похоже сам не понял, чего написал. Приведи пример использования.
Здравствуйте, Дмитро, Вы писали:
Д>Надо отметить, что так называемые виртуальные конструкторы в Borland C++ есть по смыслу ни что иное как такие вот статические виртуальные функции (синтаксис, конечно другой).
На фига подобного. Но если тебе они нужны, то я их уже изобрел Виртуальные конструкторы 2
Здравствуйте, _wqwa, Вы писали:
_>Здравствуйте, folk, Вы писали:
F>>Здравствуйте, Vi2, Вы писали:
Vi2>>>Выбор адреса функции и вызов функции с дополнительным параметром — это изначально разные вещи. Можно выбрать функцию из vtable, но не передавать туда this.
F>>Полностью согласен.
Vi2>>>Смысл? Не знаю.
F>>С твоего позволения приведу первый пришедший в голову примерчик, который демонстрирует удобство static virtual. Допустим мы хотим иметь возможность запрашивать текстовую строку — имя класса: _>примерчик скипнут
_>Будешь смеяться, но твой пример -- единственная ситуация, когда мне нужны были статичекме виртульные ф-ции. Я не видел ни одной другой задачи, для которой они бы были нужны. Если у тебя были другие задачи, где применение функций статик-виртуал было бы целесообразно -- плз, приведи пример.
Ага, значит и для тебя этот пример жизненный! Можно придумать много вариаций на его тему: вернуть указатель на коласс COM, вернуть счетчик кол-ва экземпляров класса, ... — имхо вполне распространенные ситуации.
У меня не было задач где пришлось бы использовать виртуальное наследование (тьфу-тьфу-тьфу), но ведь и оно кому-то нужно.
Здравствуйте, Alexey Shirshov, Вы писали:
AS>Здравствуйте, Дмитро, Вы писали:
AS>[]
Д>>Надо отметить, что так называемые виртуальные конструкторы в Borland C++ есть по смыслу ни что иное как такие вот статические виртуальные функции (синтаксис, конечно другой).
AS>А вот ты убери virtual! Получиться тоже самое.
В выделенной строке вызовется статический метод A::fs(). Это потому, что в методе A::fn() используется ранее связывание для вызова статического метода. Если бы использовалось позднее связываение, то вызвался бы статический метод B::fs().
Предвижу следующий совет: "Убери static и поставь virtual". К сожалению, это тоже не подходит, поскольку хотелось бы метод fs() вызывать без экземпляра, например, так: B::fs().
Д>>Можно ли без этого обойтись? Конечно можно! Для этого придумали такой паттерн как абстрактная фабрика. (В принципе, можно даже программировать в терминах машин Тьюринга, где нет ни классов, ни методов, а только лента, входные данные и текущее состояние.)
AS>Ну это ты загнул! Ты похоже сам не понял, чего написал. Приведи пример использования.
Понял. Я просто переутрировал!
То, что я хотел сказать, так это то, что все языки программрования являются выразительно равномощными. Это означает, что любой вычислительный алгоритм можно представить на любом языке. И то, что язык поддерживает ООП, шаблоны и/или "частичную специализацию" отнюдь не позволяет решать какой-то новый класс задач, недоступных для решения ранее. "Вкусности" позволяют лишь решать те же самые задачи быстрее, качественнее, надежнее. И на мой взляд "статическая виртуальность" одна из таких вкусностей.
[]
Д>В выделенной строке вызовется статический метод A::fs(). Это потому, что в методе A::fn() используется ранее связывание для вызова статического метода. Если бы использовалось позднее связываение, то вызвался бы статический метод B::fs().
Это не тот пример, который я бы хотел видеть, но все-равно. Ты говоришь о связывании. Чего с чем? Статическая функция не может быть связана. В этом весь прикол. Ее вызов определяется типом на этапе компиляции. Всегда! Тогда как определение версии вызова виртуальной функции откладывается и определяется в рантайме используя не тип, а экземпляр типа! Статическая функция не привязана к экземпляру, поэтому она никогда по определению не сможет стать виртуальной.
Д>Предвижу следующий совет: "Убери static и поставь virtual". К сожалению, это тоже не подходит, поскольку хотелось бы метод fs() вызывать без экземпляра, например, так: B::fs().
И каким образом fn вызовет B::fs() даже если ты гипотетически смог статическую функцию сдеслать виртуальной?
хъ
Д>Понял. Я просто переутрировал!
Д>То, что я хотел сказать, так это то, что все языки программрования являются выразительно равномощными. Это означает, что любой вычислительный алгоритм можно представить на любом языке. И то, что язык поддерживает ООП, шаблоны и/или "частичную специализацию" отнюдь не позволяет решать какой-то новый класс задач, недоступных для решения ранее. "Вкусности" позволяют лишь решать те же самые задачи быстрее, качественнее, надежнее. И на мой взляд "статическая виртуальность" одна из таких вкусностей.
Как это будет реализовываться. Ты говоришь, было бы неплохо вечерком, слетать на Марс или, на худой конец, Луну, а вместо этого приходится переться в кино. Ну я согласен, но приведи пример, как это может быть технически сделано.
Здравствуйте, Alexey Shirshov, Вы писали:
Д>>В выделенной строке вызовется статический метод A::fs(). Это потому, что в методе A::fn() используется ранее связывание для вызова статического метода. Если бы использовалось позднее связываение, то вызвался бы статический метод B::fs().
AS>Это не тот пример, который я бы хотел видеть, но все-равно. Ты говоришь о связывании. Чего с чем? Статическая функция не может быть связана. В этом весь прикол. Ее вызов определяется типом на этапе компиляции. Всегда! Тогда как определение версии вызова виртуальной функции откладывается и определяется в рантайме используя не тип, а экземпляр типа! Статическая функция не привязана к экземпляру, поэтому она никогда по определению не сможет стать виртуальной.
AS>И каким образом fn вызовет B::fs() даже если ты гипотетически смог статическую функцию сдеслать виртуальной?
AS>Как это будет реализовываться. Ты говоришь, было бы неплохо вечерком, слетать на Марс или, на худой конец, Луну, а вместо этого приходится переться в кино. Ну я согласен, но приведи пример, как это может быть технически сделано.
Я приведу С++'ный псевдокод и его возможную трансляцию в С.
Статическая функция по определению может быть вызвана без наличия живого экземпляра типа. Кроме этого в нее не передается указатель на этот экземпляр (т.е. метод вызова не thiscall). У тебя эти два требования не выполняються.
Т.е. статическая виртуальная функция ведет себя точно также как виртуальная. Поэтому я тебе и советовал убрать static, что приведет к тем же результатам.
В чем принципиальная сложность совместить virtual и static?
Проблема (принципиальная, еще раз подчеркну) в том, что по дизайну языка C++ static методы никогда не должны зависить от конкретного объекта, а virtual должны вызваться через виртуальную таблицу, доступ к которой осуществляется через объект.
Про это уже не раз говорили в этом топике. Приводились примеры как такой механизм реализвать, и доводы почему так делать не надо.
Пример, когда компилятор определяет "виртуальность" вызова статической функции из контекста:
1) если вызываем через объект или напрямую из нестатического вызова, то вызов через виртуальную таблицу
2) если вызов через имя класса или напрямую из статического метода, то вызов как стандартной функции.
Подобное поведение не вписывается в идиомы virtual и static (см. выше). Проблемы:
1) зависимость от контекста: перенос кода из статического метода в нестатический (или наоборот) может привести к тому, что код станет работать по-другому
2) нет транзитивности: как быть с такой цепочкой вызовов: обычный метод -> виртуальный статический->виртуальный статический? Оба статических вызова эквиваленты, но первый пойдет через виртуальную таблицу, второй напрямую.
Я уверен, что здесь куча других подводных комней. Какой бы не был базовай дизайн, действовать вопреки нему — это рыть себе могилу. Нужно придумать либо что-то другое, либо разрабавытать новыцй язык на базе C++.
А если что-то другое? Частично проблему может решить введение метакласса: виртуальные статические методы можно вызывать через его "виртаальную таблицу". Но это лишь решает проблему №1 и оставляет без решения проблему №2. И все же... создание "виртуальных конструкторов" по такой схеме — очень удобное решение. Именно так они реализованы в Делфи.
Здравствуйте, Alexey Shirshov, Вы писали:
AS>Статическая функция по определению может быть вызвана без наличия живого экземпляра типа. Кроме этого в нее не передается указатель на этот экземпляр (т.е. метод вызова не thiscall).
Согласен! Согласен и с тем, что предыдущий пример этого не демонстрирует. Исправляю свою неточность сейчас.
. . .
int main() {
//A::f_virtual_static(10); -- здесь нет живого экземпляра и указатель на него не передается.
A__f_virtual_static(10);
//B::f_virtual_static(11); -- здесь то же самое
B__f_virtual_static(11);
return 0;
}
Здравствуйте, Артур, Вы писали:
LVV>>Прощу прощения, но виртуальность-нестатичность или статичность-невиртуальность — это принципиальный вопрос семантики языка, а не доступа-реализации к функции. LVV>>Статическая функция — это функция класса. Она принципиально в одном экземпляре. LVV>>А виртуальная функция — это функция объекта. Функция класса СУЩЕСТВУЕТ ДО объявления объекта. А виртуальная функция (ну, хорошо, vtable) — только после объявления объекта. Как виртуальная функция может быть статической, если их столько, сколько объектов??????? А>Почему это vtable существует только после объявления объекта? Указатель на vtable заполняется при создании объекта, а сам виртуальная таблица генерируется для класса, и существует независимо от того, создавал ли ты объекты данного класса или нет.
Ну, хорошо, не сама vtable, а указатель на vtable. Суть от этого не меняется. Указателей столько, сколько объектов. А статическая функция — одна.
A>Я согласен с VI2, что статичность и виртуальность скорее перпендикулярные понятия,
а зависимыми они стали только благодаря реализации (vtable как член класса).
А я согласен с Павлом Кузнецовым: ПК>static означает, что функцию-член можно вызывать, не имея объекта соответствующего
класса. Виртуальный вызов подобным образом сделать принципиально невозможно.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, deviv, Вы писали:
D>2) нет транзитивности: как быть с такой цепочкой вызовов: обычный метод -> виртуальный статический->виртуальный статический? Оба статических вызова эквиваленты, но первый пойдет через виртуальную таблицу, второй напрямую.
Черт подери!!! Это пока что самый убедительный довод против "статической виртуальности"!
Слушай, ты гладко и стройно рассуждаешь, но я все равно одного не понимаю.
Как определяется класс (динамический тип), для которого вызывается функция static virtual.
Если брать эти квалификаторы по отдельности -- тут вопросов нет:
Со static -- все понятно -- какой класс в префиксе вызова указали (или какой статический тип имеет экземпляр класса или указатель, через который вызвали), для такого и вызывается.
С virtual -- тоже понятно. Берем указатель на экземпляр, смотрим его действительный класс (динамик-тайп) и для этого класса и вызываем функцию.
А если у нас нету экземпляра, откуда мы знаем, какую из множества одноименных функций-членов классов, принадлежащих одному генеалогическому дереву, сейчас надо вызвать?