[c++] почему запрещены virtual static методы?
а как ты себе их представляешь? этож в концепцию ооп не вписывается
Да, есть, но ты его не поймёшь, наверное, уже никогда, раз сейчас не понимаешь =)
---
...Я работаю антинаучным аферистом...
![](/images/icons/grin.gif)
А тебе? =)
---
...Я работаю антинаучным аферистом...
![](/images/icons/grin.gif)
Кстате, при чём тут концепция ООП? static не может быть virtual, потому что такого не может быть никогда!
Начерта они тогда?
---
...Я работаю антинаучным аферистом...
Credo.
---
...Я работаю антинаучным аферистом...
А ещё есть такой Вирт, он тоже мнимый
![](/images/icons/grin.gif)
---
...Я работаю антинаучным аферистом...
не, сигнатура как раз должна совпадать
static - не зависят от объекта
virtual - вызываются члены у соответствующего объекту класса
почему хочу статику ясно - не использует нестатических членов класса, данные объекта короч
почему виртуальную - чтобы можно было вызвать this->method в родительском классе и не париться
я где-то не прав?
чо то не понял, ты что хочешь?
class P
{
virtual static bool IsValid (int data) = 0;
void Init ;
}
void P::Init
{
if (!IsValid (0
throw E ;
...
}
class C: P {...};
вот хочу, чтобы в классе-потомке можно было определить статическую функцию IsValid и чтобы она подставлялась в C::Init
что он хочет - это понятно, чтобы, например, передавать указатель на обычную функцию внутрь другой через классовую оболочку (интерфейс). Надо сказать, вполне разумная идея. Видимо, просто её было лень реализовывать, потому как идейно это может быть и не очень правильно - всё же статические медоты нужны скорее для того, чтобы функции, нужные внутри класса, не вносили излишнюю путаницу.
ну а зачем тебе IsValid делать статическим то?
Статический метод не привязан к объекту. Ему не передаётся this. А поскольку ему не передаётся this, привязка вызова к конкретному методу (binding) не может осуществляться в рантайме, и всегда осуществляется на этапе компиляции. А virtual относится к процедуре привязки к конкретному методу в рантайме и, соответственно, не имеет никакого смысла.
А всё потому, что в Правильных Языках в принципе запрещено вызывать статические методы у объекта, всегда нужно писать название класса, а в Неправильных можно и так, и так (насколько я помню что порождает некоторое недопонимание.
Вот, даже так можно объяснить: "чтобы можно было вызвать this->method в родительском классе и не париться" - в статическом методе нет this.
чтобы сказать, что он от объекта не зависит
как такое возможно? тут ведь либо то, либо другое
1) При вызове обычного метода вызывающий метод передаёт объект, далее по объекту определяется реальный класс, для него осуществляется прогон вверх по дереву наследования до последнего виртуального неабстрактного прототипа который и вызывается, причём в качестве "нулевого параметра" (this) ему передаётся тот объект.
2) При вызове статического метода вызывающий метод никакого объекта не передаёт, вызываемый метод определён на этапе компиляции и нулевого параметра у него просто нет.
А поскольку ему не передаётся this, привязка вызова к конкретному методу (binding) не может осуществляться в рантайме, и всегда осуществляется на этапе компиляцииможет, только не осуществляется, т.к. это не нужно, если писать "класс::метод"
в Правильных Языках в принципе запрещено вызывать статические методы у объектаа что такого?
объект -> класс -> функция
да что ты ему про механизм говоришь, он идею и принцип ооп не понимает
> как такое возможно? тут ведь либо то, либо другое
Могу своё понимание выссказать.
Например, в учебных примерах по каким-нибудь чмам часто требуется передать указатель на функцию куда-то. В принципе, логично было бы вместо того, чтобы передавать указатель на функцию, запихивать в функцию указатель на объект, содержащий интерфейс к этой самой функции. Ну а по сколько, нужная нам функция по своей природе такова, что ей не нужны никакие объекты - то логично было бы сделать её статической. Иными словами, подобная конструкция нужна для того, чтобы унифицировать процесс передачи параметров в функцию.
Я на Яве слишком мало писал, поэтому не знаю - как в Яве передать куда-либо указатель на функцию? Как подобное обычно реализовывают?
ок, ну а зачем он тебе нужен, как виртуальный тогда?как виртуальный, чтобы родительской функции поставить вызов, а в рантайме уже определять для какого класса вызывать
как такое возможно? тут ведь либо то, либо другое
да, такое не возможно откомпилить. вопрос - по какой причине?
в твоем примере следует передавать в качестве параметра объект, и у объекта вызывать эту фунцию
Нет, не может, потому что нет объекта, и, соответственно, нет понятия "реальный тип".
Поясняю на примере:
class A
{
public virtual void Method
{
Console.WriteLine("A");
}
}
class B : A
{
public override void Method
{
Console.WriteLine("B");
base.Method;
}
}
class C : B
{
public override void Method
{
Console.WriteLine("C");
base.Method;
}
}
public static void Main
{
B obj = new C;
obj.Method;
}
Так вот, хотя переменная obj имеет тип B, объект в ней содержащийся имеет тип С, поэтому выведется
C
B
A
Вот.
И ещё раз: в статическом методе нет this. У статического и нестатического метода разное число параметров (имеется в виду те, которые передаются на самом деле).
Я это всё на шарпе пишу, но в плюсах механизм абсолютно тот же самый.
1) При вызове обычного метода вызывающий метод передаёт объект, далее по объекту определяется реальный класс, для него осуществляется прогон вверх по дереву наследования до последнего виртуального неабстрактного прототипа который и вызывается, причём в качестве "нулевого параметра" (this) ему передаётся тот объект.Давай на примере C++. У нас есть объект, среди его данных - указатель на таблицу указателей на виртуальные функции, которая своя для каждого класса. При этом параметры этих функций учитываются на этапе компиляции. Что нам мешает сделать так, чтобы в этой таблице хранились не только функции-члены, но и обычные статические функции? Просто компилятор должен будет учитывать этот момент...
2) При вызове статического метода вызывающий метод никакого объекта не передаёт, вызываемый метод определён на этапе компиляции и нулевого параметра у него просто нет.
А механизм я объясняю потому, что на самом деле кроме механизма ничего и нет =)
Судя по тому, что апологеты Явы отсутствие указателей записывают в преимущества языка - наверное, нельзя, но я, повторюсь, слишком поверхностно Яву знаю. Вот мне и интересно, как предлагается решать такую задачу
![](/images/graemlins/smile.gif)
![](/images/graemlins/blush.gif)
И ещё раз: в статическом методе нет this. У статического и нестатического метода разное число параметров (имеется в виду те, которые передаются на самом деле).нет this. полностью поддерживаю. но почему по this нельзя определить класс и вызвать соотв. функцию?
короче, скажи абстрактно, что ты хочешь реализовать и я скажу, как это сделать идеологически правильно с точки зрения объектного подхода
или опиши конкретно свой пример, а то я так и не понял, что ты там пытаешься изобразить
или подробнее пример написать?
вообще, сначала у меня была виртуальная функция и я не парился
потом понял, что она от объекта не зависит, поставил статику, а тут мне руки и скрутили... решил разобраться
вот это поясни, не понял
/// интерфейсный класс
class func_int{
public:
static virtual double func(double x)=0;
};
////// реализация
class fuct_1 public func_int{
double func(double x)
{return sin(x);}
};
//// функция интегрирования
double integr(fucn_int *ii)
{
int a;
double res;
for(a=0,res=0; a<1000; a++)
res+=(*ii).func(a*0.001);
return res*0.001;
}
Надеюсь не накосячил... Идея ясна?
static описывает свойства метода - передаётся или не передаётся ему this (и, соответственно, имеет ли он доступ к переменным объекта).
В принципе, наверное, можно было было бы сделать процедуру вызова несимметричной - то есть при вызове статического метода у объекта происходят действия связанные с полиморфизмом и наследованием, определяется реальный метод, дальше указатель на объект благополучно забывается и производится вызов.
Но! Это повлекло бы за собой кучу проблем. Во-первых, система становится несимметричной и вообще труднопонимаемой, ИМХО. Ошибка в регистре первой буквы (при стандартном шарповом/жавовском стиле) приводит к тотальному изменению поведения. Далее, вызываемый метод уже не может пользоваться полиморфизмом, вызывая другие методы того же объекта. То есть если для нормальных методов работают обе цепочки
A a = new B;
a.Move =(полиморфизм)=> B.Move =(вызов базового класса)=> A.Move =(вызов)=> A.Paint =(полиморфизм)=> B.Paint =(вызов базового класса)=> A.Paint
a.Paint =(полиморфизм)=> B.Paint =(вызов базового класса)=> A.Paint
То как только они становятся статическими, первая цепочка уже работает не так, а вторая - всё ещё так.
class P
{
virtual static bool IsValid (int * data) = 0;
void Init (int *);
};
void P::Init (int * data)
{
if (!IsValid (data
throw E ;
...
}
class C: P
{
static bool IsValid (int * data);
};
bool C::IsValid (int * data)
{
if (data[0] == 1)
return true;
return false;
}
C * c = new C;
теперь при вызове c->Init (data) мне нужно, чтобы использовался его IsValid
ну круто, и чо? фукция integr все пиздато считает, в чем проблема то?
ну бля, это как раз и есть зависимость, значит IsValid должен быть виртуальным
В том то и проблема, что ничего она не считает из-за "static virtual"
это как раз и есть зависимость, значит IsValid должен быть виртуальнымэто с самого начала ясно
ясно и то, что IsValid не зависит от объекта...
вот и virtual static
ну как же не зависит, если ты говоришь, что для C он у тебя должен свой быть?
A a = new B;все время впечатление, что производится срезка
![](/images/graemlins/grin.gif)
a.Move =(полиморфизм)=> B.Move =(вызов базового класса)=> A.Move =(вызов)=> A.Paint =(полиморфизм)=> B.Paint =(вызов базового класса)=> A.Paintпример оторван от интерфейса и от жизни, имхо. функции типа сдвинуть или нарисовать уж никак не статические. поэтому пример не понял
a.Paint =(полиморфизм)=> B.Paint =(вызов базового класса)=> A.Paint
То как только они становятся статическими, первая цепочка уже работает не так, а вторая - всё ещё так.
![](/images/graemlins/frown.gif)
свой, но "C" - это класс, а от объекта "c" не зависит
а функция integr должны быть описана в другом классе, class Calc_my_integr
у объекта c, экземпляра класса C должно быть особое поведение, это и значит, что оно описывается его виртуальными методами, в данном случае IsValid
В чем радость статика для виртуального метода? Искать указатель в другой таблице? Сделай конст, коли хочешь построже.
Радость статика в том, что он менее ресурсоёмок при вызове, не нужно лишний указатель передавать, который всё равно не используется. Пример я приводил в треде, когда это может быть полезно... const, вообще говоря, несколько для других целей предназначен.
![](/images/graemlins/wink.gif)
радость статика - в строгости
![](/images/graemlins/grin.gif)
короче, изучать ООП на примере C++ - это неблагодарное занятие, пишите на шарпе, яве, или любом другом правильном яп
Кстати, проясни для несведующих - что в Яве/Шарпе используется вместо C++ Templates?
В Джаве темплейтов как таковых нет. В последней версии там ввели некоторое подобие, дженерики. Раньше этого не было, поэтому шаблонный тип реализовал определённые интерфейсы.
класс описывает поведение объекта - экземпляра классаэто понятно
у объекта c, экземпляра класса C должно быть особое поведение, это и значит, что оно описывается его виртуальными методами, в данном случае IsValid
но мне нужно использовать эту функцию и без объекта... что без статика не получится
да они вообще нахер не нужны в реальной жизни, шаблоны эти
значит тебе надо два метода, один статический, который ты вызываешь из виртуальных
короче, изучать ООП на примере C++ - это неблагодарное занятие, пишите на шарпе, яве, или любом другом правильном япк сожалению, нормальных реализаций известных "правильных яп" не видел
я многого не знаю, но (подчеркиваю) наслышан, что ява - ужасно тормозная штука, а шарп - это вообще промоушн мокрософта, сырой и есть только кривые свободные поделки (какой-то моно, что-ли); он вообще открытый по спецификации?
![](/images/graemlins/smile.gif)
А вообще, в C++ изначально тоже ведь развивались объектные библиотеки, у Borland в версии 3-4 была известная Object Based Class Library, которая в пятой версии была окончательно вытеснена STL. Наверное всё же потому, что STL удобнее и быстрее... Из-за всего этого и трудно сменить C++ на Java/C#.
![](/images/graemlins/wink.gif)
Я же написал, что в Джаве есть подобие шаблонов: дженерики. Некая модель, которая проверяется на этапе компиляции. Что без шаблонов очень хорошо живётся и они в реальной жизни не нужны - это, конечно, не так. Без них не очень хорошо: и в ненужные моменты в рантайме могут вылетать исключения, и код солидно обрастает try/catch блоками.
ява - ужасно тормозная штука, а шарп - это вообще промоушн мокрософта, сырой и есть только кривые свободные поделкиДжава не тормозная. Тормозные там только GUI библиотеки. В остальном... Надо просто знать, как правильно на ней писать.
Шарп уже давно не сырой. И есть его реализация от Майкрософт. Другое дело, что эта реализация только для винды.
значит тебе надо два метода, один статический, который ты вызываешь из виртуальныхувы, пришлось сделать именно так
но это не гармонично
увы, пришлось сделать именно такНу сам посуди, что ты предлагаешь? Ты пишешь об увеличении скорости работы за счёт применения статических функций. И при этом предлагаешь вызывать их через vtable. Ты выбери что-то одно: либо тебе быстро вызывается си-подобная функция, либо компилятор лазит по vtable. Вообще, я знаю минимум трёх ООП жлобов, которые за идею применения статических функций в таком случае просто бы тебя съели.
но это не гармонично
![](/images/graemlins/smile.gif)
Джава не тормозная. Тормозные там только GUI библиотеки. В остальном... Надо просто знать, как правильно на ней писать.если я правильно понимаю, чтобы хорошо писать на яве, нужно угадывать, какой С-код стоит за вызовами используемых средств, чтобы вышло оптимальнее...
![](/images/graemlins/crazy.gif)
Шарп уже давно не сырой. И есть его реализация от Майкрософт. Другое дело, что эта реализация только для винды.значит код даже потенциально не переносим... ужас
Объясняю словами. Вот ты пишешь большую прогу на языке, позволяющем несимметричные вызовы - когда статический метод динамически биндится по объекту (кстати, практически никакого выигрыша в производительности не будет, отсутствие передачи лишнего параметра практически не роляет, одна инструкция mov, хуле).
И ты пишешь какой-нибудь статический метод, который предназначен именно для такого вызова, типа с понтом, что вызов должен спускаться вниз по иерархии объектов.
Во-первых, очень велика вероятность ошибиться и вызвать его именно статически.
Во-вторых, ты (или кто-нибудь другой, кто будет писать код на основе твоего) сделает ещё один такой же статический виртуальный метод, который будет вызывать твой. При этом без поллитры нифига не разберёшься, как именно происходит вызов.
если я правильно понимаю, чтобы хорошо писать на яве, нужно угадывать, какой С-код стоит за вызовами используемых средств, чтобы вышло оптимальнее...Нет, не нужно. Нужно понимать, что такое язык с GC, как создавать поменьше объектов, какие вещи работают принципиально быстрее. Я тебе скажу, что есть очень много задач, в которых за пять минут в лоб написанный код на Джаве или Шарпе обгонит код на С++. До тех пор, пока ты не потратишь на решение той же проблемы на С++ 4-5 часов.
значит код даже потенциально не переносим... ужасКод на Шарпе _потенциально_ вполне переносим. Опять же, С++ не является самым хорошим выбором для переносимости.
![](/images/graemlins/smile.gif)
Ну сам посуди, что ты предлагаешь? Ты пишешь об увеличении скорости работы за счёт применения статических функций. И при этом предлагаешь вызывать их через vtable. Ты выбери что-то одно: либо тебе быстро вызывается си-подобная функция, либо компилятор лазит по vtable.я предлагаю, чтобы компилятор за меня решил как оптимальнее сделать, раз мне нужны оба свойства
думаю, текущий обход гораздо менее оптимален
![](/images/graemlins/wink.gif)
вообще, оптимизация у меня на 2-м месте
главное - понятный код, имхо
мне статика в моем случае понадобилась, когда я, уже имея виртуальную IsValid, понял, что она не опирается на данные и что мне нужно ее использовать отдельно от объекта
Вообще, я знаю минимум трёх ООП жлобов, которые за идею применения статических функций в таком случае просто бы тебя съели.
![](/images/graemlins/lol.gif)
мне статика в моем случае понадобилась, когда я, уже имея виртуальную IsValid, понял, что она не опирается на данные и что мне нужно ее использовать отдельно от объектаНонсенс. Если у тебя IsValid разная для разных объектов, то это автоматически значит, что "ее использовать отдельно от объекта" нельзя. Если она у тебя одна для всех объектов, тогда пихай её в базовый класс. А если функция у тебя "пассивная", то объяви её как const.
Да нет, уже очень давно есть оформленный стандарт, и уже где-то год как релизнулась стабильная версия Mono (это типа под никсы в которой в полном объёме есть ASP, и когда я когда-то давно смотрел, чем они занимались, они радостно переходили на C# 2.0, встраивали поддержку винформ и осваивали MSBuild.
И ты пишешь какой-нибудь статический метод, который предназначен именно для такого вызова, типа с понтом, что вызов должен спускаться вниз по иерархии объектов.возможно
Во-первых, очень велика вероятность ошибиться и вызвать его именно статически.
Во-вторых, ты (или кто-нибудь другой, кто будет писать код на основе твоего) сделает ещё один такой же статический виртуальный метод, который будет вызывать твой. При этом без поллитры нифига не разберёшься, как именно происходит вызов.
дело в том, что я расцениваю static почти как const - просто некий ограничитель внутрянки, который расширяет твои возможности по использованию
иногда слишком большое расширение возможностей приводит к путанице, здесь я полностью согласен
Нонсенс. Если у тебя IsValid разная для разных объектов, то это автоматически значит, что "ее использовать отдельно от объекта" нельзя. Если она у тебя одна для всех объектов, тогда пихай её в базовый класс. А если функция у тебя "пассивная", то объяви её как const.функция IsValid зависит только от дочернего класса, но не от объекта класса
и иногда их надо использовать просто как глобальные функции (ну, в namespace, конечно)
я расцениваю static почти как const - просто некий ограничитель внутрянкиЭто совсем неправильно. Если const значит, что у тебя есть прямой (через this) доступ к членам класса, но ты их не модифицируешь; то static значит, что доступ к членам класса может быть только косвенный (передать объект вручную но при этом ты можешь изменять члены класса. И большая часть программистов в жизни не подумает, что под static ты понимал const.
Да нет, уже очень давно есть оформленный стандарт, и уже где-то год как релизнулась стабильная версия Mono (это типа под никсы в которой в полном объёме есть ASP, и когда я когда-то давно смотрел, чем они занимались, они радостно переходили на C# 2.0, встраивали поддержку винформ и осваивали MSBuild.хорошие новости
все, что я раньше слышал/читал про моно было не таким радужным
![](/images/graemlins/smirk.gif)
мне нужно ее использовать отдельно от объектаХмм. Заведи обертку chk::IsValid(const type_info &)
![](/images/graemlins/grin.gif)
Так вот нет. Создатели плюсов (равно как шарпа и жавы) назвали статическими те функции, которые ВООБЩЕ не привязаны к объектам. И ты очень неправ, что понимаешь слово static не так, как разработчики языка, разработчики компиляторов и вообще основная масса программеров на плюсах
функция IsValid зависит только от дочернего класса, но не от объекта классаЕсли у тебя две разных IsValid у двух разных дочерних классов, то "ее использовать отдельно от объекта" нельзя.
PS И вообще непонятно, в какой задаче удобно иметь функцию, которая вызывается как без объекта, так и с объектом.
Это совсем неправильно. Если const значит, что у тебя есть прямой (через this) доступ к членам класса, но ты их не модифицируешь; то static значит, что доступ к членам класса может быть только косвенный (передать объект вручную но при этом ты можешь изменять члены класса. И большая часть программистов в жизни не подумает, что под static ты понимал const.что значит "совсем"?
различие я понимаю, но ты ведь не написал, для чего это используется...
я ведь могу опустить static и const - ничего плохого не будет, если я не использовал этих "подсказок" - в этом я вижу сходство
спецификаторы позволяют шире использовать методы, но ставят ограничения на код
Так вот нет. Создатели плюсов (равно как шарпа и жавы) назвали статическими те функции, которые ВООБЩЕ не привязаны к объектам. И ты очень неправ, что понимаешь слово static не так, как разработчики языка, разработчики компиляторов и вообще основная масса программеров на плюсахтак и не понял, что именно я понимаю неправильно?
![](/images/graemlins/grin.gif)
что значит "совсем"?Даже в смысле использования совсем не верно. Модификатор const пишут, когда у тебя функция не изменяет внутренности объекта. Это чтобы программист понял, что GetSize у динамического массива не сотрёт его содержимое, например.
различие я понимаю, но ты ведь не написал, для чего это используется...
я ведь могу опустить static и const - ничего плохого не будет, если я не использовал этих "подсказок" - в этом я вижу сходство
спецификаторы позволяют шире использовать методы, но ставят ограничения на код
Модификатор static ставят тогда, когда функция никоим образом не привязана к поведению объекта. При этом она может получать объект извне и модифицировать его на своё усмотрение. Типичный пример для таких функций: создание экземпляров класса.
так и не понял, что именно я понимаю неправильно?Ты пытаешься использовать статическую функцию в том случае, когда её работа зависит от объекта.
Если у тебя две разных IsValid у двух разных дочерних классов, то "ее использовать отдельно от объекта" нельзя.можно. я предлагаю использовать со спецификатором класса (это дает статик) или резолвить в теле метода родительского класса (это вирчуал) - вот и все (т.е. в зависимости от применения)
фишка в том, что статик и вирчуал - вещи абсолютно параллельные!
И вообще непонятно, в какой задаче удобно иметь функцию, которая вызывается как без объекта, так и с объектом.она вызывается с объектом только для определения класса, из которого эту функцию вызывать
Блиа, тебе ещё в самом начале треда Ахтох нопейсал, что статические методы не привязаны к объектам, а привязаны к классам, и ООП-фишки типа полиморфизма на них просто не действуют. Так это понимают вообще ВСЕ. Ты этого не понимаешь.
можно. я предлагаю использовать со спецификатором класса (это дает статик) или резолвить в теле метода родительского класса (это вирчуал) - вот и все (т.е. в зависимости от применения)Фишка в том, что статик и виртуал вещи абсолютно перпендикулярные. Виртуальная функция опирается на объект, статическая - нет.
фишка в том, что статик и вирчуал - вещи абсолютно параллельные!
Даже в смысле использования совсем не верно. Модификатор const пишут, когда у тебя функция не изменяет внутренности объекта. Это чтобы программист понял, что GetSize у динамического массива не сотрёт его содержимое, например.я вижу главное применение этих двух в том, чтобы компилятор понял что-то, а потом уж программист
Модификатор static ставят тогда, когда функция никоим образом не привязана к поведению объекта. При этом она может получать объект извне и модифицировать его на своё усмотрение. Типичный пример для таких функций: создание экземпляров класса.
если бы конст и статик не давали преимуществ (вызов для константного объекта и без объекта то их попросту ленились бы использовать
я вижу главное применение этих двух в том, чтобы компилятор понял что-то, а потом уж программистНет, ты опять недопонимаешь. Есть необходимость: например, создание первого экземпляра главного класса программы происходит в статической функции. Или если тебе нужно контролировать процесс создания классов: можно объявить конструктор протектедом, и позволять создавать класс только через вызов статической функции.
если бы конст и статик не давали преимуществ (вызов для константного объекта и без объекта то их попросту ленились бы использовать
Блиа, тебе ещё в самом начале треда Ахтох нопейсал, что статические методы не привязаны к объектам, а привязаны к классам, и ООП-фишки типа полиморфизма на них просто не действуют. Так это понимают вообще ВСЕ. Ты этого не понимаешь.я понимаю, что так есть
не понимаю почему?
если уж разрешили использовать this->static_method, так вызывайте правильный метод!
я вижу главное применение этих двух в том, чтобы компилятор понял что-то, а потом уж программистЗдесь ты зря так. Static - даёт преимущества тем, что не передаётся указатель на объект, хотя преимущество здесь - невелико обычно. Декларативное - тоже минимально, впрочем.
если бы конст и статик не давали преимуществ (вызов для константного объекта и без объекта то их попросту ленились бы использовать
Const же - исключительно декларативен, для программиста, компилятор разве что не даст сделать явной ошибки. Но в другом функции с const и обычное - ничем не отличаются.
Нет, ты опять недопонимаешь. Есть необходимость: например, создание первого экземпляра главного класса программы происходит в статической функции. Или если тебе нужно контролировать процесс создания классов: можно объявить конструктор протектедом, и позволять создавать класс только через вызов статической функции.ну так это все подходит под то, что я написал
есть необходимость - люди ставят спецификаторы и все
что же я недопонимаю?
я вижу главное применение этих двух в том, чтобы компилятор понял что-то, а потом уж программист
если бы конст и статик не давали преимуществ (вызов для константного объекта и без объекта то их попросту ленились бы использовать
ну так это все подходит под то, что я написалТак ты определись: необходимость для программиста или чтобы комплятор что-то понял. Не ленятся использовать как правило static именно из-за того, что он не привязан к объекту. И каково бы ни было описание вызова статического метода, он (метод) всё равно не связан с объектом.
есть необходимость - люди ставят спецификаторы и все
что же я недопонимаю
Static - даёт преимущества тем, что не передаётся указатель на объект, хотя преимущество здесь - невелико обычно. Декларативное - тоже минимально, впрочем.разве я не о том же написал: "преимуществ (вызов ... без объекта)"?
Const же - исключительно декларативен, для программиста, компилятор разве что не даст сделать явной ошибки. Но в другом функции с const и обычное - ничем не отличаются.ага. именно поэтому я удивлялся сообщениям компилятора на ранней стадии изучения плюсов, когда он не давал мне вызвать не const функцию на константном объекте
ошибка хоть и явная, ее надо исключать
Нет, я не понимаю, о чём мы говорим... Вызов статической функции происходит без объекта, в то время как вызов обычной - с передачей указателя на уже созданный объект. В этом и есть главный плюс статической функции. Тут до меня дошло, в чём проблема с витруальной статической функцией (я тормозил): Смотри. Есть объект, уже созданный - принципиально то, что указатель на таблицу виртуальных функций - это один из элементов этого объекта! То есть, не создав объект, мы не можем узнать, где находится таблица виртуальных функций, и из-за этого не можем вызвать эту самую статическую виртуальную функцию без объекта. То есть, теоретически это дело можно обойти, но дополнительная работа - слишком большая, и оно того не стоит.
Так ты определись: необходимость для программиста или чтобы комплятор что-то понял.понимание компилятора влечет запреты и необходимость для программиста
![](/images/graemlins/smile.gif)
понимание компилятора влечет запреты и необходимость для программистаПричину и следствие местами не меняй. Это программисту нужно какое-то поведение. И он говорит компилятору, каким это поведение должно быть.
Тут до меня дошло, в чём проблема с витруальной статической функцией (я тормозил): Смотри. Есть объект, уже созданный - принципиально то, что указатель на таблицу виртуальных функций - это один из элементов этого объекта! То есть, не создав объект, мы не можем узнать, где находится таблица виртуальных функций, и из-за этого не можем вызвать эту самую статическую виртуальную функцию без объекта. То есть, теоретически это дело можно обойти, но дополнительная работа - слишком большая, и оно того не стоит.это понятно, но я ведь делаю не так
у меня фактически два применения функции, не связанных друг с другом
1. отдельно от всего - тогда C::IsValid - вопросов нет
2. внутри функции род. класса P, т.е. this->IsValid - т.е. уже объект есть (this) и у него можно посмотреть таблицу
это понятно, но я ведь делаю не такЁлы палы. Тебе уже сколько раз сказали? Ну нету привязки к объекту при вызове this->IsValid если IsValid статическая. Понимаешь? В этом и есть смысл static. Джава или Шарп не дадут тебе так написать вообще, и это правильно. Жаль, что в С++ нету ограничения, оно сбивает с толку новичков.
у меня фактически два применения функции, не связанных друг с другом
1. отдельно от всего - тогда C::IsValid - вопросов нет
2. внутри функции род. класса P, т.е. this->IsValid - т.е. уже объект есть (this) и у него можно посмотреть таблицу
Ты же предлагаешь фактически, чтобы в некоторых случаях static функции опирались на объект. В этом и есть полное противоречие.
Причину и следствие местами не меняй. Это программисту нужно какое-то поведение. И он говорит компилятору, каким это поведение должно быть.но предварительно программисту не дал компилятор что-то сделать и он полез менять спецификаторы
так что я не меняю, просто у тебя вторая часть цепочки
Да, это можно сделать.
Но код в результате превратится в спагетти.
![](/images/graemlins/crazy.gif)
Ну нету привязки к объекту при вызове this->IsValid если IsValid статическая. Понимаешь? В этом и есть смысл static.Понимаю. Ну вот ты, здравый человек, когда тебе напишут this->IsValid ты какую из объявленных статических функций вызовешь?
Жаль, что в С++ нету ограничения, оно сбивает с толку новичков.+1
Можно... Но всё же, это лишняя работа, некоторая дополнительная путаница... То есть "овчинка не стоит выделки", я так думаю. Я могу описать ситуации, когда подобное будет удобнее своей наглядностью...
Понимаю. Ну вот ты, здравый человек, когда тебе напишут this->IsValid ты какую из объявленных статических функций вызовешь?Я буду считать, что вызывают нестатическую функцию и очень удивлюсь, если она окажется статической. После чего я отфакторю всё дерево классов, связанных с этой бредятиной и сделаю cvs commit.
Чувак говорит о том, что когда у нас уже ЕСТЬ объект, можно засунуть ему в vmt указатели на статические методы тоже. И обрабатывать вызовы с использованием полиморфизма, а потом просто не передавать указатель на объект.спасибо. хоть кто-то меня понял
![](/images/graemlins/wink.gif)
кстати, написав обход я именно это и сделал, только функций две
Да, это можно сделать.не доказано.
Но код в результате превратится в спагетти.
![](/images/graemlins/grin.gif)
если я пишу virtual static...то всё ещё не понимаю, что такое virtual и что такое static.
![](/images/graemlins/mad.gif)
![](/images/graemlins/laugh.gif)
спасибо всем за обсуждение! считаю тему закрытой...
открывается конкурс на лучшее обходное решение
![](/images/graemlins/grin.gif)
![](/images/graemlins/grin.gif)
![](/images/graemlins/grin.gif)
Завести в качестве public-переменной указатель на функцию, который присваивать - в конструкторе... Хотя традиционный подход (правда для несколько иных ситуаций, чем ты описываешь - это уже ближе к моему примеру) - просто завести виртуальную функцию, которая будет возвращать указатель на функцию. Типа свой маленький COM.
Остаётся подвести итог. Есть три случая:
1. Во время выполнения тебе нужно точно знать класс объекта (чтобы вызвать именно его метод) - используешь virtual
2а. Во время выполнения тебе не нужно точно знать класс объекта. Метод базового класса тебя вполне устраивает - не пишешь ни virtual, ни static. Даже самые оголтелые сторонники ООП (и Java, в частности) не могут обходиться без этого случая. Хотя бы чтобы вызвать нужный конструктор.
2б. Во время выполнения тебе вааще не нужен объект - используешь static.
Для выбора одного из этих трёх (непересекающихся, заметь) вариантов машине нужно как минимум 2 бита. Однако 2 бита могут быть в четырёх состояниях, и уж прости, что это четвёртое, о котором ты говоришь, запрещено. Так вышло.
В Java с указателями на функции никаких проблем. В твоём случае это может выглядеть например так:
public interface Integrable {
public double function(double arg);
}
public class MyMegaIntegrator {
public double integrate(Integrable integrable) {
...
y = integrable.function(x);
....
}
}
public class Test {
public static double megaFunction(double arg) {
...
}
public static void main(String[] args) {
MyMegaIntegrator integrator = new MyMegaIntegrator;
double integral = integrator.integrate(new Integrable {
public double function(double arg) {
return megaFunction(arg);
}
});
}
}
увы, пришлось сделать именно такписать функцию Init вместо конструктора -- вот это негармонично. А все эти твои static virtual...
но это не гармонично
PS. Я фигею, 100 постов на такую тему!..
Завести в качестве public-переменной указатель на функцию, который присваивать - в конструкторе... Хотя традиционный подход (правда для несколько иных ситуаций, чем ты описываешь - это уже ближе к моему примеру) - просто завести виртуальную функцию, которая будет возвращать указатель на функцию. Типа свой маленький COM.можно и так
в любом случае нужно заботиться о лишнем при описании дочернего класса, явно указывать - "ты, пожалуйста, используй эту статическую функцию, чтобы выполнялся полиморфизм при вызове от объекта" - как ни оберни это
![](/images/graemlins/frown.gif)
я так до сих пор и не понял, почему мне нужно извращаться в моем случае, дублировать функцию или использовать указатель на функцию (что почти одно и то же)
ведь противоречий не возникает при использовании virtual+static. запретили бы тогда вызывать от объекта - и дело с концом... зачем нужна запись obj->static_function при отсутствии virtual-static функций не понятно...
![](/images/graemlins/confused.gif)
писать функцию Init вместо конструктора -- вот это негармонично.естественно у меня в реальном примере не init...
назови ее xxx, так понятнее? вижу, ты не умеешь концентрироваться на проблеме
Для выбора одного из этих трёх (непересекающихся, заметь) вариантов машине нужно как минимум 2 бита. Однако 2 бита могут быть в четырёх состояниях, и уж прости, что это четвёртое, о котором ты говоришь, запрещено. Так вышло.хорошее сравнение про биты, именно так себе и представляю
цель треда была - выяснить, почему так вышло и связано это или нет с конкретными реализациями компиляторов
Ещё напрашивается аналогия с far/near, cdecl/pascal, auto/static, signed/unsigned и т. д.
Представляешь, как было бы удобно - скажем, переменная создаётся в стеке (auto но помнит (static) своё значение...
![](/images/graemlins/smile.gif)
А всего-то надо было бы написать:
auto static int i;
template<class TType>
class A
{
public:
virtual void IsValid(int data)
{
T::IsValid(data);
}
static void IsValid(int data){}
};
class C1:
public A<C1>
{
public:
static void IsValid(int data)
{
//bla-bla 1
}
};
class C2:
public A<C2>
{
public:
static void IsValid(int data)
{
//bla-bla 2
}
};
в Java/C#:
class A
{
public virtual void IsValid(int data)
{
A::IsValid(data);
}
public static void IsValid(int data){}
}
class C1: A
{
public override void IsValid(int data)
{
C1::IsValid(data);
}
public static void IsValid(int data)
{
//bla-bla 1
}
}
class C2: A
{
public override void IsValid(int data)
{
C2::IsValid(data);
}
public static void IsValid(int data)
{
//bla-bla 2
}
}
только так нельзя перегружать функции:
virtual void IsValid(int data)
{
T::IsValid(data);
}
static void IsValid(int data){}
но идея ясна
минус только в том, что шаблоны сложнее отлаживать
![](/images/graemlins/frown.gif)
ведь противоречий не возникает при использовании virtual+staticЛол! Ты вообще читать умеешь? Тебе же разжевали дальше некуда, почему возникают противоречия.
Лол! Ты вообще читать умеешь? Тебе же разжевали дальше некуда, почему возникают противоречия.удивишься, но умею! мне разжевали определения, которые я и так знал. никто не привел примера, где неясно как использовать virtual static функцию. собственно, мне его и хотелось получить, когда я писал первый пост
Какие тебе ещё объяснения нужны?
Если бы всё было так, как ты и хотел, то есть статики лежали в каком-то особенном месте vtable, то менялась бы сама семантика статических функций - они бы были связаны с объектами. То есть виртуальную функцию никакими ухищрениями нельзя сделать статической, даже путём изменения стандарта.
class A
{
public virtual static IsValid
{
}
}
class B:A
{
public override static IsValid
{
}
}
пример 1:
A a = new A;
a.IsValid;
пример 2:
B b = new B;
b.IsValid;
пример 3:
B b = new B;
Execute(b);
void Execute(A a)
{
a.IsValid;
}
Какой из методов, ты хочешь, чтобы в каждом из вариантов был вызван (A.IsValid или B.IsValid)?
Её никак нельзя использовать, потому что vtable - часть объекта, а статические функции с объектами не связаны.Перечитай тред, если осилишь... Все эти моменты уже обсудили, и не один раз.
Какие тебе ещё объяснения нужны?
Если бы всё было так, как ты и хотел, то есть статики лежали в каком-то особенном месте vtable, то менялась бы сама семантика статических функций - они бы были связаны с объектами. То есть виртуальную функцию никакими ухищрениями нельзя сделать статической, даже путём изменения стандарта.
Если кратно - отличие статической функции от простой функции-члена (не важно, виртуальная она или нет) - в том, что в обычной функции неявно передаётся указатель на объект. Поэтому простую функцию без объекта вызвать принципиально невозможно. Допустим, у нас есть виртуальная функция член - тогда её проблема состоит только в том, что не понятно, как её найти без таблицы указателей на виртуальные функции, но если знать, где она лежит - то её можно вызвать и без объекта. То есть, это тем не менее - полноценная статическая функция, просто появляются некоторые дополнительные проблемы с нахождением указателя на неё. То есть, подобное вполне реально реализовать, однако проблема, как мне сейчас кажется - что просто было лень заморачиваться подобными нетривиальными конструкциями, которые, при этом, нужны достаточно редко... Тем более, что можно было много других вещей доработать, если бы большое желание было, вместо этого.
По-моему, гражданин просто ж0стко прикалывается. Сколько раз сказано - переопределять статические функции в производных классах никто не запрещает, ты только пальцем покажи, какую именно (какого именно класса) статический метод с этим именем ты хочешь вызвать; если же на этапе компиляции этого сказать нельзя, а надо смотреть, какого конкретно класса данный объект, значит, нужен this (ну, чтобы как-то обозначить этот конкретный объект). А this и static - вещи взаимоисключающие. Чё не понятно-то?
у тебя логическая ошибка
Ошибка ты хотел сказать?
Вот это вот не понятно:
> А this и static - вещи взаимоисключающие.
Что такое static (применительно к Ф-Ч)? В случае, если функция не виртуальная, а обычная Ф-Ч - то этоо такая функция, которая не получает указателя на объект в качестве параметров. Теперь добавляем слово virtual - по определению и смыслу этого слова, для того, чтобы обратиться к функции, необходимо посмотреть на таблицу виртуальных функций соответствующего объекта.
То есть:
Механизм виртуальных функций срабатывает ДО запуска кода функции, его суть, смысл заключается в том, чтобы получить указатель на функцию по объекту - после того, как этот указатель найден, виртуальную функцию нельзя отличить от обычной, они на следующем этапе будут ИДЕНТИЧНЫМИ.
Механизм статических функций срабатывает во время запуска функции (при передачи параметров в стек и по ходу всего исполнения функции, так как компилятор внутри функции не имеет указателя на объект.
Таким образом, слова virtual и static - не противоречат друг другу! Да, virtual накладывает некоторые ограничения и вносит дополнительную путаницу - но явных противоречий здесь нет! Это не антонимы, это просто разные механизмы разного назначения.
Или если тебе нужно контролировать процесс создания классов: можно объявить конструктор протектедом, и позволять создавать класс только через вызов статической функции.
а как запрещать создание не через конструктор? в java и с++
По объекту, но не по this? Как это?
Видишь ли перед вызовом метода указатель на данный объект можно
- либо поместить в стек
- либо не помещать в стек
Если функция static, она указатель в стек не помещает. Если нет - помещает, даже самая что ни на есть virtual. Как совместить эти два действия, я не понимаю.
> Если функция static, она указатель в стек не помещает. Если нет - помещает, даже самая что ни на есть virtual.
> Как совместить эти два действия, я не понимаю
А в чем проблема?
Вот, допустим есть код вида
class m_class{ public:
int var1;
m_class
{var1=13666;}
virtual int func1(int x)
{ printf("%d",x); }
virtual static int func2(int x)
{ printf("%d",x); }
};
///////
m_class aa;
После создания объект представляет из себя кусок с двумя переменными - переменной var1, и переменной v_ptr (где хранится сама таблица виртуальных функций - не помню, вроде она одна на весь класс, а не на кажный объект, но могу ошибаться, и это не принципиально). Далее, мы хотим вызвать aa.func1(10). При этом КОМПИЛЯТОР делает следующее:
считывает неявную переменную aa.v_ptr, после чего подставляет call-вызов функции aa.v_ptr[0], запихнув в стек дополнительно 2 переменные - переменную this, и переменную x. Ну, обычный вызов обычной статической функции. Теперь, допустим, мы должны вызвать условную статическую виртуальную функцию. Что должен делать КОМПИЛЯТОР - считать неявную переменную aa.v_ptr (как и раньше подставить call - вызов функции aa.v_ptr[1], но при этом в стек запихивать this ему не нужно! Да, чтобы вызвать функцию - указатель на созданный объект нужен, но только потому, что иначе нельзя установить, где лежит указатель на функцию. После того, как указатель получен - знать об объекте ничего не нужно.
ОК. Убедил.
1 - A
Какой из методов, ты хочешь, чтобы в каждом из вариантов был вызван (A.IsValid или B.IsValid)?
2 - B
3 - B
в общем, как при полиморфизме
идея такова для virtual static (раз разрешили зачем-то использовать запись obj->stat_func)
если используется класс::функция - то понятно какой код исполнять еще на этапе компиляции
если написано объект->функция, то, все-таки, хотелось бы видеть полиморфные свойства
как такую идею реализовать - хорошо написал
на данный момент запись obj->stat_func только вводит в заблуждение и может привести к ошибкам
подозреваю, что virtual static запретили, чтобы тем, кто привык, что про статику все известно на этапе компиляции, было удобнее
вообще, имхо, статик для метода класса должен означать лишь то, что данные объекта не используется, даже если он участвует в вызове - в общем-то у Бьерна именно так и написано
никто не привел примера, где неясно как использовать virtual static функциюЛогично что из одной static virtual функции может вызываться другая static virtual функция? И она должна вызывать "правильная", так ведь? Поэтому не передавать указатель на объект нельзя, а значит можно без ущерба с точки зрения оптимизации слово static стереть.
Логично что из одной static virtual функции может вызываться другая static virtual функция? И она должна вызывать "правильная", так ведь? Поэтому не передавать указатель на объект нельзя, а значит можно без ущерба с точки зрения оптимизации слово static стереть.Нет, логичным было бы, что в силу этого из такой виртуальной статической функции нельзя было бы вызвать другую виртуальную функцию (в том числе статическую). Да, дополнительное ограничение, но не принципиальное... То есть понятно, что из-за подобных ограничений полезность подобных функций уменьшается, но это не значит, что они совсем уж бесполезны... Просто нерациональны.
Нет, логичным было бы, что в силу этого из такой виртуальной статической функции нельзя было бы вызвать другую виртуальную функцию (в том числе статическую). Да, дополнительное ограничение, но не принципиальное... То есть понятно, что из-за подобных ограничений полезность подобных функций уменьшается, но это не значит, что они совсем уж бесполезны... Просто нерациональны.достаточно использовать для вызова вирчуал-статик методов только 2 записи: класс::функция, объект->функция, а остальные считать ошибочными.
т.к. в статической функции нельзя использовать this, привязка к объекту нам не нужна внутри такой функции и все вызовы в-с функций внутри будут однозначно определены
в этом случае полезность остается прежней
![](/images/graemlins/laugh.gif)
Перечитай тред, если осилишь... Все эти моменты уже обсудили, и не один раз.Чуве, я в курсе, что такое статик и как оно работает. Отвечать, не прочитав всего треда, тоже не имею привычки. Поэтому не надо рассказывать мне вкратце, что было раньше. Я это и сам сделал своим постом.
где хранится сама таблица виртуальных функций - не помню, вроде она одна на весь класс, а не на кажный объект, но могу ошибаться, и это не принципиальноТы ошибаешься, она на каждый объект, и это принципиально. То есть доступа к виртуальной функции нельзя получить без объекта. Запись вида имя_класса::имя_виртуальной_статической_функции не имеет смысла. Или ты предлагаешь ещё и имена статических функций хранить в двух местах?
То есть, приплюснутые насильники нагло лгут,
когда говорят про сильную типизацию.
---
...Я работаю антинаучным аферистом...
Неправда. Таблица общая на все объекты класса. В самих объектах хранится только указатель на неё.
> Запись вида имя_класса::имя_виртуальной_статической_функции не имеет смысла.
Неправда. Компилятору известны адреса функций, больше здесь ничего не требуется.
Почему насильники? Куда делись боевики? На другую траву перешёл? Или сменил психиатра?
---
...Я работаю антинаучным аферистом...
Тогда получится, что из такого метода - мы не сможем вызывать другие виртуальные методы, в том числе - даже virtual static, т.е. решение получается незамкнутое.
мы не сможем вызывать другие виртуальные методы, в том числе - даже virtual staticЯ им уже говорил. , что в этом их "исчислении" логично будет запретить вызывать из static (даже virtual) что-то зависящее от объекта, в частности, virtual (даже static). Вот такой замкнутый круг хехе
![](/images/graemlins/ooo.gif)
Что мешает вызвать virtual static метод? Отсутствие объекта не проблема, если известен нужный класс (типичный случай - вызов метода предка). Если же класс не известен и никакого объекта нет, то проблема не в методе, а в постановке задачи, где требуется такой вызов непонятно зачем совершить.
Ошибочка вышла: virtual static зависит не от объекта, а только от его типа. Разница принципиальная.
Ну придумай сам конкретную задачу. Например, затасканную иерархию форм. Пусть статическая виртуальная функция пишет: "Я прямоугольник" или "Я круг".
// Что мешает вызвать virtual static метод? Отсутствие объекта не проблема, если известен нужный класс
Если известен (при компиляции) нужный класс, то мы пишем:
НужныйКласс::нужныйМетод(...);. Если не изветен, то нужен this, причем именно this, а не какое-то производное знание вроде названия класса, так как мы тут же захотим вызывать другие виртуальные статические методы.
Не надо причину со следствием путать.
Правильный подход выглядит так: сначала ставится задача, потом определяются средства решения. Здесь почему-то упорно предлагается всё вывернуть наизнанку: сначала берётся метод, а потом под него подгоняется какая-то неудобная задача, причём даже не задача, а нечто с шапкозакидательской аргументацией ("так как мы тут же захотим ...").
Просто статические методы широко используются без всяких this, и это не является проблемой. virtual static отличается лишь в одном: его можно вызывать не только напрямую, но и через чью-нибудь VMT.
Мне сложно представить задачу, где понадобился бы virtual static, разве что какая-нибудь отладка или низкоуровневые извраты, но это совсем не значит, что такой механизм не имеет права на существование. Да, его возможности ограничены, но не более того.
В жизни используется много правильных подходов.
Это правильный - инженерный подход, когда сначала определяется что мы хотим решить, а потом - как.
Есть еще правильный - научный/теоретический подход, когда изучаются и определяются средства, а уже потом ищутся задачи, для решения которых мы эти средства можем использовать.
> и определяются средства, а уже потом ищутся задачи
Сразу видно математика.
---
"Унивеpситет pазвивает все способности, в том числе глупость."
А. Чехов
Кстати, в стандарте, раздел 10.3, пункт 7 как раз говорится о том, почему нельзя употреблять vitrual static.
> Ты ошибаешься, она на каждый объект, и это принципиально.Ладно, сойдёмся на том, что в стандарте это не оговорено, и реализовано может быть и тем и другим способами.
Неправда. Таблица общая на все объекты класса. В самих объектах хранится только указатель на неё.
Стандарт приводит тоже самое рассуждение: если без объекта нельзя сделать вызов, то функция не может быть статической. С технической точки зрения утверждение неверно, что здесь уже подробно расписали. С точки зрения ООП - другой вопрос, наверное, есть какие-то грабли.
Поиск в гугле даёт ссылки на различные обсуждения данного вопроса, но разгребать всё это пока желания нет.
бля, понаписали тут, а на мой вопрос не ответили, как запретить не через конструктор экземпляр создавать? в c++ и java
Это, видимо, еще более жесткий каламбур?
C myObj = C::construct(myParm);
а внутри construct в зависимости от параметра создается экземпляр одного из потомков, ну и еще что-нибудь делается типа инициализации
как мне запретить вызов new для потомка не из конструктора?
Вчера ночью точно так же, как и ты, написал на С++. Приводить не стал по одной причине: для передачи указателя на класс куда-либо, придётся делать ещё один базовый класс для "template<class TType>class A". Что в общем-то выглядит менее красиво, чем виртуальная функция, вызывающая статическую.
Объявить конструкторы потомков protected/private, сделать базовый класс friend'ом.
это в C++? а в java как?
Объявить у дочерних классов конструкторы с доступом в пределах пакета.
А что поконкретнее ты хочешь? Вроде сделал свой класс final, и все свободны. Или не сделал final. Но тогда у тебя ещё 2 опции: public class или /* package */ class, как уже сказал .
По-моему, один из нас идиот. Вроде все согласились, что можно не помещать в (или, скорее выталкивать из, для тех у кого есть только стек; ну как в Форте) стек this специально для virtual static метода. Но совсем без this не обойтись. А раз так, зачем делать вид, что его нет?
Когда ты это поймёшь?
Самокритично.
> Вроде все согласились, что можно не помещать в (или, скорее выталкивать из, для тех у кого есть только стек; ну как в Форте) стек this специально для virtual static метода.
Cогласились, я разве с этим спорю?
> Но совсем без this не обойтись.
Очень даже обойтись. virtual static можно использовать, как обычный static, что указывалось в этом треде очень много раз.
> А раз так, зачем делать вид, что его нет?
Не так.
> Когда ты это поймёшь?
В своей башке сначала порядок наведи.
имя_класса::имя_виртуальной_статической_функции(...)от имя_класса::имя_статической_функции(...) ?
Ничем.
А зачем тогда слово "virtual"?
Чтобы при вызове вида obj->static_virtual_method метод выбирался в зависимости от типа объекта, на который указывает obj в процессе выполнения кода.
obj->static_virtual_methodКак ты думаешь, что значит, "obj->" для процессора? Т.е., какими инструкциями ты бы это представил на ассемблере? Хоть на каком-нибудь: Intel, MSIL, JVM...
---
...Я работаю антинаучным аферистом...
Само по себе ничего не значит. А вот для компилятора значит. В случае просто static метода, его адрес будет определён сразу по типу указателя и сгенерирован прямой вызов. От virtual static ожидается вызов через таблицу виртуальных методов объекта.
> Как ты думаешь, что значит, "obj->" для процессора?
Имеется в виду, что если присутствует такая запись, со ссылкой на объект - то значит сам объект существует, и из него можно извлечь указатель на таблицу виртуальных функций (тем же образом, как и извлекается указатель для обычных виртуальных функций). Если же конкретного объекта нет (например, хочется вызвать одну статическую функцию из другой то вызов можно производить лишь по записи вида class_name::static_virtual_method.
Минуя this?
вот так (псевдокод):
объявления:
class objtype;
objtype* obj;
вызовы:
; obj->method;
push obj
call objtype::method
; obj->static_method;
call objtype::static_method
; obj->virtual_method;
mov r0, [obj+vmt_offset] ; адрес VMT
mov r1, [r0+virtual_method_index] ; адрес метода
push obj
call r1
; obj->virtual_static_method;
mov r0, [obj+vmt_offset]
mov r1, [r0+virtual_static_method_index]
call r1
А этот вот obj, который мелькает в ассемблерном коде, это часом не this, без которого, по твоим словам, можно обойтись?
Для кого-то он, безусловно, this, в частности, для самого obj. Для куска кода, в котором делаются эти вызовы - совсем не обязательно.
Конструктор (в терминологии C++) имеет те же модификаторы доступа, что и остальные методы, так что вопрос удивителен. Ответ, впрочем, дали.
ОК, спасибо, ясно.
![](/images/graemlins/smile.gif)
Виртуальные методы отличаются тем, что вызываются в соответствии с настоящим классом объекта, даже если обращение происходит через указатель на предка класса объекта. Для этого каждый объект с виртуальными методами содержит в качестве данных таблицу виртуальных методов и вызов происходит через эту таблицу (из таблицы берётся указатель на метод и делается косвенный вызов).
Таким образом, для того, чтобы метод был виртуальным, нужно чтобы указатель на этот метод был в любом объекте класса (внутри таблицы виртуальных функций). Статические функции не имеют доступа к объекту (так как не получают указатель на него в качестве аргумента а значит, не имеют доступа к таблице виртуальных методов, значит не могут быть виртуальными. Более того, обращение к статическим методам и переменным возможно и в случае отсутствия вообще объектов класса.
В принципе, можно сделать, чтобы статические методы были виртуальными, но это на мой взгляд не имеет практического смысла.
Ты бы перед своим постом написал "всё предыдущее ниасилил, многа букф".
![](/images/graemlins/lol.gif)
> даже если обращение происходит через указатель
> каждый объект [...] содержит в качестве данных таблицу виртуальных методов
> из таблицы берётся указатель
Ладно, это всё детали реализации, а семантически это как?
---
...Я работаю антинаучным аферистом...
class A {На C++ с включённым RTTI должно быть что-то похожее.
public static void f {
System.out.println("From A!");
}
}
class B extends A {
public static void f {
System.out.println("From B!");
}
}
public class Simple extends B {
public static void main(String[] args) throws Exception {
A a = new Simple;
a.getClass.getMethod("f", new Class[0]).invoke(null, new Object[0]);
}
}
Семантически выражение «virtual static» противоречиво.
На С++ подобное решение будет гораздо тяжелее.
Проблемы людей, которые хотят сэкономить на push obj, продолжая копаться в таблице виртуальных функций, мне вообще не понять. Это был чисто теоретический изыск.
Java. Мы не торопимся.А вот это очень и очень зря. Потому что из-за тонн тормозного Джава кода этот язык считают тормозным и убогим.
---
"I will use smilies every time I am joking. I will use smilies.."
В Delphi есть "virtual static" функции - это называется virtual class function. Используются они не часто. Основной их смысл в том, что этим функциям вместо указателя на объект передается указатель на таблицу виртуальных методов (в частности из них можно вызывать другие class function и конструкторы, а обычные методы вызывать, разумеется, нельзя). В С++ их нет, потому что язык развивался по-другому и теперь уже сложно что-либо изменить.
Оставить комментарий
a10063
имеется ввиду вопрос не про конкретную реализацию компиляторов сегодня, а какие причины побудили это запретить (если не ошибаюсь, в стандарте)есть ли какой-то пример, где virtual и static конфликтуют?