В чем принципиальная сложность совместить virtual и static?
Проблема (принципиальная, еще раз подчеркну) в том, что по дизайну языка C++ static методы никогда не должны зависить от конкретного объекта, а virtual должны вызваться через виртуальную таблицу, доступ к которой осуществляется через объект.
Про это уже не раз говорили в этом топике. Приводились примеры как такой механизм реализвать, и доводы почему так делать не надо.
Пример, когда компилятор определяет "виртуальность" вызова статической функции из контекста:
1) если вызываем через объект или напрямую из нестатического вызова, то вызов через виртуальную таблицу
2) если вызов через имя класса или напрямую из статического метода, то вызов как стандартной функции.
Подобное поведение не вписывается в идиомы virtual и static (см. выше). Проблемы:
1) зависимость от контекста: перенос кода из статического метода в нестатический (или наоборот) может привести к тому, что код станет работать по-другому
2) нет транзитивности: как быть с такой цепочкой вызовов: обычный метод -> виртуальный статический->виртуальный статический? Оба статических вызова эквиваленты, но первый пойдет через виртуальную таблицу, второй напрямую.
Я уверен, что здесь куча других подводных комней. Какой бы не был базовай дизайн, действовать вопреки нему — это рыть себе могилу. Нужно придумать либо что-то другое, либо разрабавытать новыцй язык на базе C++.
А если что-то другое? Частично проблему может решить введение метакласса: виртуальные статические методы можно вызывать через его "виртаальную таблицу". Но это лишь решает проблему №1 и оставляет без решения проблему №2. И все же... создание "виртуальных конструкторов" по такой схеме — очень удобное решение. Именно так они реализованы в Делфи.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>Их комбинация невозможна (и не нужна)
А по-моему пригодилась бы.
Пусть внутри функции this не нужен, но вызов конкретной переопределенной реализации должен осуществляться на основе динамического типа экземпляра (если экземпляра нет, то явной квалификацией класса).
Не слишком сумбурно изложил?
Ну почему же невозможна?! static означает, что у метода нет первого параметра this (ну или метод не с thiscall calling convention). virtual означает, что доступ к такой функции может быть через vtable.
По-моему, это перпендикулярные свойства — одно другому не мешает. И вполне могут быть представлены.
Здравствуйте, MByte, Вы писали:
ME>>А зачем тебе такое?
MB>Как-то спросили меня, а я не знал что ответить.С тех пор ищу ответ.Просто интересно.Программируя на С++ даже не задумывался про такую конструкцию.Вот здесь http://cprime.hypermart.net/rus/lesson/21.htm нашел пример.Но сделать свой не смог.
А там же написано:
Однако то, что мы сейчас сделали, компилироваться не будет. Дело в том, что статические функции (объявленные как static) не могут быть виртуальными.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>static означает, что функцию-член можно вызывать, не имея объекта соответствующего ПК>класса. Виртуальный вызов подобным образом сделать принципиально невозможно.
По-моему, Vi2 имел в виду (концептуально, а не применительно к Си++) такую трактовку статического метода: метод, чье действие не зависит от состояния конкретного объекта.
Например, в те времена, когда не было typeid и иже с ним, многие библиотеки содержали самодельные средства RTTI. Классы содержали метод вроде virtual RuntimeClass* GetType() const. Такому методу безразлично состояние (но не динамический тип) конкретного объекта, к которому он применен, и он "статический" в этом смысле.
Здравствуйте, Alexey Shirshov, Вы писали:
Д>>В выделенной строке вызовется статический метод A::fs(). Это потому, что в методе A::fn() используется ранее связывание для вызова статического метода. Если бы использовалось позднее связываение, то вызвался бы статический метод B::fs().
AS>Это не тот пример, который я бы хотел видеть, но все-равно. Ты говоришь о связывании. Чего с чем? Статическая функция не может быть связана. В этом весь прикол. Ее вызов определяется типом на этапе компиляции. Всегда! Тогда как определение версии вызова виртуальной функции откладывается и определяется в рантайме используя не тип, а экземпляр типа! Статическая функция не привязана к экземпляру, поэтому она никогда по определению не сможет стать виртуальной.
AS>И каким образом fn вызовет B::fs() даже если ты гипотетически смог статическую функцию сдеслать виртуальной?
AS>Как это будет реализовываться. Ты говоришь, было бы неплохо вечерком, слетать на Марс или, на худой конец, Луну, а вместо этого приходится переться в кино. Ну я согласен, но приведи пример, как это может быть технически сделано.
Я приведу С++'ный псевдокод и его возможную трансляцию в С.
Объясните пожалуйста что это такое и с чем его едят.
Везде пишут только про простые static или virtual функции.
Можно ли использовать такие конструкции?Пробовал методом проб и ошибок, но ничего не вышло, компилятор посылает меня с моими функциями очень далеко.
И еще вопрос раз уже дорвался до форума.Как можно использовать virtual для множественного наследования?Если это все возможно, то хотелось бы увидеть реальные примеры с объяснением.
Буду очень признателен за просвещение или ссылку где можно это все почерпнуть.
Заранее спасибо.
Здравствуйте, LCR, Вы писали:
LCR>Здравствуйте, MaximE, Вы писали:
ME>>Как раз для этой цели используют идиому double dispatch.
LCR>MaximE, можно по-подробнее. Что это за идиома?
Паттерн visitor использует идиому double dispatch:
L_L>Я о том, что для выбора нужной функции нужен объект — он содержит вптр, который указывает на втбл, в которой "адрес нужной функции". Т.е. о таком
Выбор адреса функции и вызов функции с дополнительным параметром — это изначально разные вещи. Можно выбрать функцию из vtable, но не передавать туда this. Смысл? Не знаю.
Здравствуйте, Vi2, Вы писали:
ПК>> static означает, что функцию-член можно вызывать, не имея объекта ПК>> соответствующего класса. Виртуальный вызов подобным образом сделать ПК>> принципиально невозможно.
V> Виртуальный вызов нельзя сделать при полном описании имени, даже с V> объектом. Что из этого следует? Ничего.
Это немного о другом. Просто, если ввести возможность указывать и virtual, и static
одновременно, как ты предлагаешь, получившиеся функции перестанут быть статическими
(т.к. их нельзя будет вызывать без объекта), не приобретя ничего по сравнению с обычными
виртуальными, кроме того, что this в них доступен не будет.
Posted via RSDN NNTP Server 1.6 RC1
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Vi2, Вы писали:
Vi2>Выбор адреса функции и вызов функции с дополнительным параметром — это изначально разные вещи. Можно выбрать функцию из vtable, но не передавать туда this.
Полностью согласен.
Vi2>Смысл? Не знаю.
С твоего позволения приведу первый пришедший в голову примерчик, который демонстрирует удобство static virtual. Допустим мы хотим иметь возможность запрашивать текстовую строку — имя класса:
1. динамически — у экземпляра
2. статически — у класса (например где-нибудь в шаблонных глубинах экземпляр недоступен, но известен класс, специализирующий этот шаблон)
Динамический вызов: pObj->typeName(). При этом методу передается this, который ему совершенно не нужен.
Статический вызов в глубинах шаблона: typename T::typeNameStatic()
Указатель на typeName() присутствует в таблице виртуальных функций, поэтому можем вызывать так: pObj->typeName()
И в то же время поскольку этой функции не передается неявный параметр this, то где-нибудь в шаблоне можем написать так: typename T::typeName()
Здравствуйте, folk, Вы писали:
F>Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>>Их комбинация невозможна (и не нужна)
F>А по-моему пригодилась бы. F>Пусть внутри функции this не нужен, но вызов конкретной переопределенной реализации должен осуществляться на основе динамического типа экземпляра (если экземпляра нет, то явной квалификацией класса).
Как раз для этой цели используют идиому double dispatch.
Здравствуйте, Vi2, Вы писали:
V> Ну почему же невозможна?! static означает, что у метода нет первого V> параметра this (ну или метод не с thiscall calling convention). V> virtual означает, что доступ к такой функции может быть через vtable.
static означает, что функцию-член можно вызывать, не имея объекта соответствующего
класса. Виртуальный вызов подобным образом сделать принципиально невозможно.
Posted via RSDN NNTP Server 1.6 RC1
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, MaximE, Вы писали:
ME>Здравствуйте, MByte, Вы писали:
MB>>Буду очень признателен за просвещение или ссылку где можно это все почерпнуть.
ME>Может стоит купить хорошую книжку по c++, например Страуструпа?
У меня есть Страуструп, но там я нашел только описание virtual и static.Их комбинации нигде не видел, тем более с примерами.Может плохо искал.Искал в интернете.Результат ноль.Все тыкают куда угодно, говорят мол есть такое, а рассказать толком, да еще и примеры привести никто не может.Все только умничать и умеют.Устал искать уже, вот и решил закинуть вопрос на форум.
MB>>> Буду очень признателен за просвещение или ссылку где можно это все MB>>> почерпнуть. ME>> Может стоит купить хорошую книжку по c++, например Страуструпа? M> У меня есть Страуструп, но там я нашел только описание virtual и M> static.Их комбинации нигде не видел, тем более с примерами.Может плохо M> искал.Искал в интернете.Результат ноль.Все тыкают куда угодно, говорят M> мол есть такое, а рассказать толком, да еще и примеры привести никто не M> может.Все только умничать и умеют.Устал искать уже, вот и решил закинуть M> вопрос на форум.
Статические функции (класса) не могут быть виртуальными
Здравствуйте, MByte, Вы писали:
MB>Здравствуйте, MaximE, Вы писали:
ME>>Здравствуйте, MByte, Вы писали:
MB>>>Буду очень признателен за просвещение или ссылку где можно это все почерпнуть.
ME>>Может стоит купить хорошую книжку по c++, например Страуструпа?
MB>У меня есть Страуструп, но там я нашел только описание virtual и static.Их комбинации нигде не видел, тем более с примерами.Может плохо искал.Искал в интернете.Результат ноль.Все тыкают куда угодно, говорят мол есть такое, а рассказать толком, да еще и примеры привести никто не может.Все только умничать и умеют.Устал искать уже, вот и решил закинуть вопрос на форум.
Такая комбинация невозможна. Для работы виртуальной функции необходим доступ к таблице виртуальных функций класса. Этот доступ возможен только через указатель на эту таблицу (по крайней мере во многих реализациях это так), а указатель содержится в каждом объекте. static же функция ни с какими объектами дела не имеет, а посему не имеет возможности добраться до таблицы.
Здравствуйте, MByte, Вы писали:
MB>У меня есть Страуструп, но там я нашел только описание virtual и static.Их комбинации нигде не видел, тем более с примерами.Может плохо искал.Искал в интернете.Результат ноль.Все тыкают куда угодно, говорят мол есть такое, а рассказать толком, да еще и примеры привести никто не может.Все только умничать и умеют.Устал искать уже, вот и решил закинуть вопрос на форум.
Статические функции не могут быть виртуальными, а виртуальные — статическими. Поэтому и нет нигде ничего.
А что вообще за проблема, зачем вдруг понадобилось?
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, MByte, Вы писали:
MB>У меня есть Страуструп, но там я нашел только описание virtual и static.Их комбинации нигде не видел, тем более с примерами.Может плохо искал.Искал в интернете.Результат ноль.Все тыкают куда угодно, говорят мол есть такое, а рассказать толком, да еще и примеры привести никто не может.Все только умничать и умеют.Устал искать уже, вот и решил закинуть вопрос на форум.
Вот твое исходное высказывание PM>>> Статические функции (класса) не могут быть виртуальными
Из него можно сделать при желании неверный вывод, что статические функции (не класса — т.е. с внутренней компоновкой)могут быть виртуальными
Of course, the code must be complete enough to compile and link.
Здравствуйте, MaximE, Вы писали:
ME>Здравствуйте, MByte, Вы писали:
MB>>У меня есть Страуструп, но там я нашел только описание virtual и static.Их комбинации нигде не видел, тем более с примерами.Может плохо искал.Искал в интернете.Результат ноль.Все тыкают куда угодно, говорят мол есть такое, а рассказать толком, да еще и примеры привести никто не может.Все только умничать и умеют.Устал искать уже, вот и решил закинуть вопрос на форум.
ME>А зачем тебе такое?
Как-то спросили меня, а я не знал что ответить.С тех пор ищу ответ.Просто интересно.Программируя на С++ даже не задумывался про такую конструкцию.Вот здесь http://cprime.hypermart.net/rus/lesson/21.htm нашел пример.Но сделать свой не смог.
Здравствуйте, MByte, Вы писали:
MB>Здравствуйте, MaximE, Вы писали:
ME>>Здравствуйте, MByte, Вы писали:
MB>>>У меня есть Страуструп, но там я нашел только описание virtual и static.Их комбинации нигде не видел, тем более с примерами.Может плохо искал.Искал в интернете.Результат ноль.Все тыкают куда угодно, говорят мол есть такое, а рассказать толком, да еще и примеры привести никто не может.Все только умничать и умеют.Устал искать уже, вот и решил закинуть вопрос на форум.
ME>>А зачем тебе такое?
MB>Как-то спросили меня, а я не знал что ответить.С тех пор ищу ответ.Просто интересно.Программируя на С++ даже не задумывался про такую конструкцию.Вот здесь http://cprime.hypermart.net/rus/lesson/21.htm нашел пример.Но сделать свой не смог.
LL> Вот твое исходное высказывание PM>>>> Статические функции (класса) не могут быть виртуальными LL> Из него можно сделать при желании неверный вывод, что статические LL> функции (не класса — т.е. с внутренней компоновкой)могут быть LL> виртуальными
уел
Здравствуйте, LaptevVV, Вы писали:
LVV>Здравствуйте, MByte, Вы писали:
ME>>>А зачем тебе такое?
MB>>Как-то спросили меня, а я не знал что ответить.С тех пор ищу ответ.Просто интересно.Программируя на С++ даже не задумывался про такую конструкцию.Вот здесь http://cprime.hypermart.net/rus/lesson/21.htm нашел пример.Но сделать свой не смог.
LVV>А там же написано: LVV>Однако то, что мы сейчас сделали, компилироваться не будет. Дело в том, что статические функции (объявленные как static) не могут быть виртуальными.
С этим более менее понятно, а что насчет множественного наследования с помощью virtual?
Здравствуйте, MByte, Вы писали:
LVV>>А там же написано: LVV>>Однако то, что мы сейчас сделали, компилироваться не будет. Дело в том, что статические функции (объявленные как static) не могут быть виртуальными.
MB>С этим более менее понятно, а что насчет множественного наследования с помощью virtual?
Тут я пока пас — не приходилось использовать на практике. Но в теории виртуальное множественное наследование применяется, чтобы избежать проблемы ромбика, когда от одного класса сначала наследуют два, а потом от этих двух наследует один.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, MByte, Вы писали:
MB>Здравствуйте, LaptevVV, Вы писали:
LVV>>Здравствуйте, MByte, Вы писали:
ME>>>>А зачем тебе такое?
MB>>>Как-то спросили меня, а я не знал что ответить.С тех пор ищу ответ.Просто интересно.Программируя на С++ даже не задумывался про такую конструкцию.Вот здесь http://cprime.hypermart.net/rus/lesson/21.htm нашел пример.Но сделать свой не смог.
LVV>>А там же написано: LVV>>Однако то, что мы сейчас сделали, компилироваться не будет. Дело в том, что статические функции (объявленные как static) не могут быть виртуальными.
MB>С этим более менее понятно, а что насчет множественного наследования с помощью virtual?
Прикинь, разрабатываешь оконное GUI типа Виндов. И вот у тебя есть три типа окон: просто окно(прямоугольник, текст заголовка,...) (class Window), и два его потомка — окно с меню (Window_with_menu) и окно с полосой прокрутки ( Window_with_scroll). И пришла тебе идея создать окно с меню и с прокруткой. Самый простой путь —
class Window_with_menu_and_scroll : public Window_with_menu, public Window_with_scroll
{
...
}
Но если так, то в каждом экземпляре Window_with_menu_and_scroll будет ДВА экземпляра Window: из Window_with_menu
и из Window_with_scroll. И как тогда его рисовать (Window_with_menu_and_scroll ) ?
А если
class Window_with_menu_and_scroll : public virtual Window_with_menu, public virtual Window_with_scroll
{
...
}
то в Window_with_menu_and_scroll будет только одна копия Window, что и требовалось.
В Страуструпе (гл. 15, по-моему,"Иерархия классов") есть еще пара примеров, довольно небесполезных.
Здравствуйте, Bell, Вы писали:
B>Здравствуйте, MByte, Вы писали:
MB>>Здравствуйте, MaximE, Вы писали:
ME>>>Здравствуйте, MByte, Вы писали:
MB>>>>Буду очень признателен за просвещение или ссылку где можно это все почерпнуть.
ME>>>Может стоит купить хорошую книжку по c++, например Страуструпа?
MB>>У меня есть Страуструп, но там я нашел только описание virtual и static.Их комбинации нигде не видел, тем более с примерами.Может плохо искал.Искал в интернете.Результат ноль.Все тыкают куда угодно, говорят мол есть такое, а рассказать толком, да еще и примеры привести никто не может.Все только умничать и умеют.Устал искать уже, вот и решил закинуть вопрос на форум.
B>Такая комбинация невозможна. Для работы виртуальной функции необходим доступ к таблице виртуальных функций класса. Этот доступ возможен только через указатель на эту таблицу (по крайней мере во многих реализациях это так), а указатель содержится в каждом объекте. static же функция ни с какими объектами дела не имеет, а посему не имеет возможности добраться до таблицы.
Вот если бы gcc-шный typeof был бы в стандарте,
и был полноценно реализован (с учётом rtti), то
можно было бы сказать, что у виртуальных классов статические функции виртуальны
class A{
public:
virtual void stub(){}
static void test(){}
};
class B:public A{
public:
virtual void stub(){}
static void test(){}
};
int main()
{
B b;
A* a=&b;
typeof(*a)::test();
}
10.3/7
... Nor can a virtual function be a static member, since a virtual function call relies on a specific object for determining wich function to invoke...
Of course, the code must be complete enough to compile and link.
Здравствуйте, Vi2, Вы писали:
Vi2>Здравствуйте, Lorenzo_LAMAS, Вы писали:
Vi2>
L_L>>Их комбинация невозможна
Vi2>Ну почему же невозможна?! static означает, что у метода нет первого параметра this (ну или метод не с thiscall calling convention). virtual означает, что доступ к такой функции может быть через vtable. Vi2>По-моему, это перпендикулярные свойства — одно другому не мешает. И вполне могут быть представлены.
Здравствуйте, LCR, Вы писали:
LCR>Здравствуйте, MaximE, Вы писали:
ME>>Как раз для этой цели используют идиому double dispatch.
LCR>MaximE, можно по-подробнее. Что это за идиома?
Причем здесь vtable и this? vtable нужен при вызове метода через указатель pObj->Func(); Внутри самой функции this может и не требоваться если стоит static.
Что не знаете, что static функцию можно звать и так
CSomeClass pObj = ...;
pObj->SomeFunc();
и так
CSomeClass::SomeFunc();
Точно также виртуальную функцию можно звать. По крайней мере на вид они похожи. Единственное отличие — во втором случае требуется объект, так это нужно для thiscall вызова.
Vi2>Точно также виртуальную функцию можно звать. По крайней мере на вид они похожи. Единственное отличие — во втором случае требуется объект, так это нужно для thiscall вызова.
Это нужно чтобы выбрать правильную версию виртуальной функции.
Of course, the code must be complete enough to compile and link.
L_L>Это нужно чтобы выбрать правильную версию виртуальной функции.
Версия виртуальной функции не зависит от static (или того помещается ли адрес первым аргументом или нет).
Вернемся к предыдущим примерам
CSomeClass pObj = ...;
pObj -> SomeFunc(...);
и так
pObj -> CSomeClass::SomeFunc(...);
Что можно сказать о таких функциях? Да ничего. Они могут быть как виртуальными/невиртуальными, так и татеческими/нестатическими. Поэтому вполне допустима виртуальная статическая функция, просто при ее вызове не передается первый параметр. Хотя вызов может осуществляться через vtable.
ПК>static означает, что функцию-член можно вызывать, не имея объекта соответствующего
ПК>класса. Виртуальный вызов подобным образом сделать принципиально невозможно.
Виртуальный вызов нельзя сделать при полном описании имени, даже с объектом. Что из этого следует? Ничего.
pObj -> CObjClass::SomeVirtMethod(...);
Чем это отличается от
pObj -> CObjClass::SomeStaticMethod(...);
А не имея объекта, невозможно не только вызвать виртуальный метод, но и просто нестатический метод. Тут виртуальность как бы сбоку. Но если есть объект, то и виртуальный вызов можно сделать, и статический.
Здравствуйте, Vi2, Вы писали:
Vi2>Версия виртуальной функции не зависит от static (или того помещается ли адрес первым аргументом или нет).
Vi2>Вернемся к предыдущим примерам Vi2>
Vi2>Что можно сказать о таких функциях? Да ничего. Они могут быть как виртуальными/невиртуальными, так и татеческими/нестатическими. Поэтому вполне допустима виртуальная статическая функция, просто при ее вызове не передается первый параметр. Хотя вызов может осуществляться через vtable.
Vi2>То, что это не реализовано, это-то ясно.
Прощу прощения, но виртуальность-нестатичность или статичность-невиртуальность — это принципиальный вопрос семантики языка, а не доступа-реализации к функции.
Статическая функция — это функция класса. Она принципиально в одном экземпляре.
А виртуальная функция — это функция объекта. Функция класса СУЩЕСТВУЕТ ДО объявления объекта. А виртуальная функция (ну, хорошо, vtable) — только после объявления объекта. Как виртуальная функция может быть статической, если их столько, сколько объектов???????
Она потому и названа виртуальной, что меняется от объекта к объекту.
И как тогда Вы будете понимать такой термин: СТАТИЧЕСКАЯ ЧИСТАЯ ВИРТУАЛЬНАЯ функция?
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
LVV>Прощу прощения, но виртуальность-нестатичность или статичность-невиртуальность — это принципиальный вопрос семантики языка, а не доступа-реализации к функции. LVV>Статическая функция — это функция класса. Она принципиально в одном экземпляре. LVV>А виртуальная функция — это функция объекта. Функция класса СУЩЕСТВУЕТ ДО объявления объекта. А виртуальная функция (ну, хорошо, vtable) — только после объявления объекта. Как виртуальная функция может быть статической, если их столько, сколько объектов???????
Почему это vtable существует только после объявления объекта? Указатель на vtable заполняется при создании объекта, а сам виртуальная таблица генерируется для класса, и существует независимо от того, создавал ли ты объекты данного класса или нет. Если не ошибаюсь, виртуальная таблица существует даже для абстрактных классов, объектов которых и быть не может. Я согласен с VI2, что статичность и виртуальность скорее перпендикулярные понятия, а зависимыми они стали только благодаря реализации (vtable как член класса).
Перечитал и понял что могут не так понять. 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() даже если ты гипотетически смог статическую функцию сдеслать виртуальной?
хъ
Д>Понял. Я просто переутрировал!
Д>То, что я хотел сказать, так это то, что все языки программрования являются выразительно равномощными. Это означает, что любой вычислительный алгоритм можно представить на любом языке. И то, что язык поддерживает ООП, шаблоны и/или "частичную специализацию" отнюдь не позволяет решать какой-то новый класс задач, недоступных для решения ранее. "Вкусности" позволяют лишь решать те же самые задачи быстрее, качественнее, надежнее. И на мой взляд "статическая виртуальность" одна из таких вкусностей.
Как это будет реализовываться. Ты говоришь, было бы неплохо вечерком, слетать на Марс или, на худой конец, Луну, а вместо этого приходится переться в кино. Ну я согласен, но приведи пример, как это может быть технически сделано.
Статическая функция по определению может быть вызвана без наличия живого экземпляра типа. Кроме этого в нее не передается указатель на этот экземпляр (т.е. метод вызова не thiscall). У тебя эти два требования не выполняються.
Т.е. статическая виртуальная функция ведет себя точно также как виртуальная. Поэтому я тебе и советовал убрать static, что приведет к тем же результатам.
Здравствуйте, 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 -- тоже понятно. Берем указатель на экземпляр, смотрим его действительный класс (динамик-тайп) и для этого класса и вызываем функцию.
А если у нас нету экземпляра, откуда мы знаем, какую из множества одноименных функций-членов классов, принадлежащих одному генеалогическому дереву, сейчас надо вызвать?
Здравствуйте, Дмитро, Вы писали:
Д>Здравствуйте, deviv, Вы писали:
D>>2) нет транзитивности: как быть с такой цепочкой вызовов: обычный метод -> виртуальный статический->виртуальный статический? Оба статических вызова эквиваленты, но первый пойдет через виртуальную таблицу, второй напрямую.
Д>Черт подери!!! Это пока что самый убедительный довод против "статической виртуальности"!
Но я придумал workaround. Он заключается а том, чтобы неявно передавать адрес таблицы виртуальных методов с "статический виртуальный" метод.
По порядку. Итак, для начала введем такое понятие как класс-метод. Это понятие вводится в дополнение к обычному статическому методу.
Класс-метод похож на обычный статический метод тем, что он может быть вызван вне контекста какого-либо объекта и поэтому из него нельзя доступиться к нестатическим членам-данным.
Класс-метод отличается от обычного статического метода тем, что из него можно вызвать виртуальный класс-метод используя таблицу виртуальных методов. Он как бы "помнит" в контексте какого класса он был вызван. Фактически, в него неявно передается указатель на таблицу виртуальных методов.
Класс-методы могут быть как виртуальными, так и невиртуальными. Невиртуальные класс-методы не имеют соответствующей записи в таблице виртуальных методов и поэтому могут быть вызваны только напрямую. Виртуальные класс-методы могут быть вызваны и через таблицу виртеальных методов, и напрямую.
Класс-методы могут быть вызваны из обычных методов и из класс-методов, и не могут быть вызваны из статических методов без явного указания класса, в контексте которого они вызываются.
Из класс-методов можно вызывать класс-методы и статические методы, но нельзя вызывать обычные методы без явного указания объекта, к которому они применяются.
Здравствуйте, _wqwa, Вы писали:
_>Здравствуйте, Дмитро, Вы писали:
_>Слушай, ты гладко и стройно рассуждаешь, но я все равно одного не понимаю. _>Как определяется класс (динамический тип), для которого вызывается функция static virtual.
_>Если брать эти квалификаторы по отдельности -- тут вопросов нет: _>Со static -- все понятно -- какой класс в префиксе вызова указали (или какой статический тип имеет экземпляр класса или указатель, через который вызвали), для такого и вызывается. _>С virtual -- тоже понятно. Берем указатель на экземпляр, смотрим его действительный класс (динамик-тайп) и для этого класса и вызываем функцию.
_>А если у нас нету экземпляра, откуда мы знаем, какую из множества одноименных функций-членов классов, принадлежащих одному генеалогическому дереву, сейчас надо вызвать?
Если указан класс в префиксе -- вызываем метод того класса, какой указан.
Если класс не указан, но вызов производится из обычного метода -- адрес метода выбираем из таблицы виртуальных методов.
Если класс не указан, но вызов производится из внешней функции -- ошибка компиляции (как и при вызове обычного статического метода)
Вообще-то проблема неожиданно возникла при вызове "статического виртуального" метода из "статического виртуального", либо просто статического. Re: virtual static и static virtual (by deviv)
При этом в той схеме, которой я указал ранее, терялась информация о типе и вложенный вызов "статического виртуального" уже не мог быть сделан правильно.
f> поскольку этой функции не передается неявный параметр this, то f> где-нибудь в шаблоне можем написать так: typename T::typeName()
Но, без объекта, эта штуковина вернет результат вызова функции, соответствующей статическому типу T, т.к. без объекта не сможет добраться до vtbl.
И зачем оно такое, загадочное, нужно?..
Posted via RSDN NNTP Server 1.6 RC1
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
f>> поскольку этой функции не передается неявный параметр this, то f>> где-нибудь в шаблоне можем написать так: typename T::typeName()
ПК>Но, без объекта, эта штуковина вернет результат вызова функции, соответствующей ПК>статическому типу T, т.к. без объекта не сможет добраться до vtbl.
Ну разумеется.
ПК>И зачем оно такое, загадочное, нужно?..
Оно не намного загадочнее вызова константного или неконстантного метода в зависимости от константности this. ИМХО.
Если говорить об этом примере, то статический вызов может использоваться в шаблоне, создающем экземпляры, или в шаблоне, выводящем статистическую информащию (например кол-во экземпляров). В обоих этих случаях тип известен, а экземпляр не нужен.
Д>Если указан класс в префиксе -- вызываем метод того класса, какой указан. Д>Если класс не указан, но вызов производится из обычного метода -- адрес метода выбираем из таблицы виртуальных методов. Д>Если класс не указан, но вызов производится из внешней функции -- ошибка компиляции (как и при вызове обычного статического метода)
Олрайт, теперь понял. Правда, большого смысла в этом не вижу... Ну да это уже мое личное мнение