[c++] почему запрещены virtual static методы?

a10063

имеется ввиду вопрос не про конкретную реализацию компиляторов сегодня, а какие причины побудили это запретить (если не ошибаюсь, в стандарте)
есть ли какой-то пример, где virtual и static конфликтуют?

otvertka07

а как ты себе их представляешь? этож в концепцию ооп не вписывается

bleyman

Да, есть, но ты его не поймёшь, наверное, уже никогда, раз сейчас не понимаешь =)

Ivan8209

Слабо объяснить?
---
...Я работаю антинаучным аферистом...

otvertka07

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

bleyman

А тебе? =)

Ivan8209

А я не знаю.
---
...Я работаю антинаучным аферистом...

otvertka07

объясняю на пальцах, что такое ООп: есть объект, у объекта есть методы, все они виртуальные, а еще есть статические методы, с объектами связаны чисто формально и вообще к ООП никакого отношения не имеют

bleyman

Ну видишь ли, раз он уже знает слова "static" и "virtual", и даже знает, что написано в стандарте, значит, он уже читал книжку.
Кстате, при чём тут концепция ООП? static не может быть virtual, потому что такого не может быть никогда!

Ivan8209

Что означает "виртуальные"? Мнимые, что ли?
Начерта они тогда?
---
...Я работаю антинаучным аферистом...

Ivan8209

> static не может быть virtual, потому что такого не может быть никогда!
Credo.
---
...Я работаю антинаучным аферистом...

bleyman

=)
А ещё есть такой Вирт, он тоже мнимый

otvertka07

не мнимые, а полиморфные

Ivan8209

"Полиморфные" --- это как? С изменяемой сигнатурой?
---
...Я работаю антинаучным аферистом...

otvertka07

не, сигнатура как раз должна совпадать

a10063

почему ж не вписывается?
static - не зависят от объекта
virtual - вызываются члены у соответствующего объекту класса
почему хочу статику ясно - не использует нестатических членов класса, данные объекта короч
почему виртуальную - чтобы можно было вызвать this->method в родительском классе и не париться
я где-то не прав?

otvertka07

чо то не понял, ты что хочешь?

a10063

для примера:

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

alexkravchuk

что он хочет - это понятно, чтобы, например, передавать указатель на обычную функцию внутрь другой через классовую оболочку (интерфейс). Надо сказать, вполне разумная идея. Видимо, просто её было лень реализовывать, потому как идейно это может быть и не очень правильно - всё же статические медоты нужны скорее для того, чтобы функции, нужные внутри класса, не вносили излишнюю путаницу.

otvertka07

ну а зачем тебе IsValid делать статическим то?

bleyman

>> почему хочу статику ясно - не использует нестатических членов класса, данные объекта короч
Статический метод не привязан к объекту. Ему не передаётся this. А поскольку ему не передаётся this, привязка вызова к конкретному методу (binding) не может осуществляться в рантайме, и всегда осуществляется на этапе компиляции. А virtual относится к процедуре привязки к конкретному методу в рантайме и, соответственно, не имеет никакого смысла.
А всё потому, что в Правильных Языках в принципе запрещено вызывать статические методы у объекта, всегда нужно писать название класса, а в Неправильных можно и так, и так (насколько я помню что порождает некоторое недопонимание.
Вот, даже так можно объяснить: "чтобы можно было вызвать this->method в родительском классе и не париться" - в статическом методе нет this.

a10063

чтобы сказать, что он от объекта не зависит

otvertka07

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

bleyman

Да блин, механизм вызова совершенно разный.
1) При вызове обычного метода вызывающий метод передаёт объект, далее по объекту определяется реальный класс, для него осуществляется прогон вверх по дереву наследования до последнего виртуального неабстрактного прототипа который и вызывается, причём в качестве "нулевого параметра" (this) ему передаётся тот объект.
2) При вызове статического метода вызывающий метод никакого объекта не передаёт, вызываемый метод определён на этапе компиляции и нулевого параметра у него просто нет.

a10063

А поскольку ему не передаётся this, привязка вызова к конкретному методу (binding) не может осуществляться в рантайме, и всегда осуществляется на этапе компиляции
может, только не осуществляется, т.к. это не нужно, если писать "класс::метод"
в Правильных Языках в принципе запрещено вызывать статические методы у объекта
а что такого?
объект -> класс -> функция

otvertka07

да что ты ему про механизм говоришь, он идею и принцип ооп не понимает

alexkravchuk

> ок, ну а зачем он тебе нужен, как виртуальный тогда?
> как такое возможно? тут ведь либо то, либо другое
Могу своё понимание выссказать.
Например, в учебных примерах по каким-нибудь чмам часто требуется передать указатель на функцию куда-то. В принципе, логично было бы вместо того, чтобы передавать указатель на функцию, запихивать в функцию указатель на объект, содержащий интерфейс к этой самой функции. Ну а по сколько, нужная нам функция по своей природе такова, что ей не нужны никакие объекты - то логично было бы сделать её статической. Иными словами, подобная конструкция нужна для того, чтобы унифицировать процесс передачи параметров в функцию.
Я на Яве слишком мало писал, поэтому не знаю - как в Яве передать куда-либо указатель на функцию? Как подобное обычно реализовывают?

a10063

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

otvertka07

хм, а в яве разве можно передать указатель на функцию?
в твоем примере следует передавать в качестве параметра объект, и у объекта вызывать эту фунцию

bleyman

>> может, только не осуществляется, т.к. это не нужно, если писать "класс::метод"
Нет, не может, потому что нет объекта, и, соответственно, нет понятия "реальный тип".
Поясняю на примере:
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. У статического и нестатического метода разное число параметров (имеется в виду те, которые передаются на самом деле).
Я это всё на шарпе пишу, но в плюсах механизм абсолютно тот же самый.

alexkravchuk

1) При вызове обычного метода вызывающий метод передаёт объект, далее по объекту определяется реальный класс, для него осуществляется прогон вверх по дереву наследования до последнего виртуального неабстрактного прототипа который и вызывается, причём в качестве "нулевого параметра" (this) ему передаётся тот объект.
2) При вызове статического метода вызывающий метод никакого объекта не передаёт, вызываемый метод определён на этапе компиляции и нулевого параметра у него просто нет.
Давай на примере C++. У нас есть объект, среди его данных - указатель на таблицу указателей на виртуальные функции, которая своя для каждого класса. При этом параметры этих функций учитываются на этапе компиляции. Что нам мешает сделать так, чтобы в этой таблице хранились не только функции-члены, но и обычные статические функции? Просто компилятор должен будет учитывать этот момент...

bleyman

Ни в яве, ни в шарпе нельзя передавать указатель на функцию. Для этого используется специальный тип объектов - delegate, которые инкапсулируют указатель на объект и что-то типа указателя на функцию.
А механизм я объясняю потому, что на самом деле кроме механизма ничего и нет =)

alexkravchuk

> хм, а в яве разве можно передать указатель на функцию?
Судя по тому, что апологеты Явы отсутствие указателей записывают в преимущества языка - наверное, нельзя, но я, повторюсь, слишком поверхностно Яву знаю. Вот мне и интересно, как предлагается решать такую задачу

a10063

не понял, к чему этот пример
И ещё раз: в статическом методе нет this. У статического и нестатического метода разное число параметров (имеется в виду те, которые передаются на самом деле).
нет this. полностью поддерживаю. но почему по this нельзя определить класс и вызвать соотв. функцию?

otvertka07

короче, скажи абстрактно, что ты хочешь реализовать и я скажу, как это сделать идеологически правильно с точки зрения объектного подхода

otvertka07

или опиши конкретно свой пример, а то я так и не понял, что ты там пытаешься изобразить

a10063

так вот, я же привел урезанный пример реальной ситуации
или подробнее пример написать?
вообще, сначала у меня была виртуальная функция и я не парился
потом понял, что она от объекта не зависит, поставил статику, а тут мне руки и скрутили... решил разобраться

otvertka07

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

вот это поясни, не понял

alexkravchuk

вот пример: нужно написать функцию вычисления определённого интеграла. Пусть для простоты - интеграл от [0;1], методом прямоугольников (по первой точке число шагов=1000. Функция интегрирования должна получить каким-то образом в качестве параметра функцию, которую нужно интегрировать. Создадим для этой цели интерфейсный класс (ну непонтово просто указатель на функцию передавать)

/// интерфейсный класс
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;
}

Надеюсь не накосячил... Идея ясна?

bleyman

Ага. Я понял, что вы имеете в виду, и, наверное, я был не прав.
static описывает свойства метода - передаётся или не передаётся ему this (и, соответственно, имеет ли он доступ к переменным объекта).
В принципе, наверное, можно было было бы сделать процедуру вызова несимметричной - то есть при вызове статического метода у объекта происходят действия связанные с полиморфизмом и наследованием, определяется реальный метод, дальше указатель на объект благополучно забывается и производится вызов.
Но! Это повлекло бы за собой кучу проблем. Во-первых, система становится несимметричной и вообще труднопонимаемой, ИМХО. Ошибка в регистре первой буквы (при стандартном шарповом/жавовском стиле) приводит к тотальному изменению поведения. Далее, вызываемый метод уже не может пользоваться полиморфизмом, вызывая другие методы того же объекта. То есть если для нормальных методов работают обе цепочки
A a = new B;
a.Move =(полиморфизм)=> B.Move =(вызов базового класса)=> A.Move =(вызов)=> A.Paint =(полиморфизм)=> B.Paint =(вызов базового класса)=> A.Paint
a.Paint =(полиморфизм)=> B.Paint =(вызов базового класса)=> A.Paint
То как только они становятся статическими, первая цепочка уже работает не так, а вторая - всё ещё так.

a10063


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

otvertka07

ну круто, и чо? фукция integr все пиздато считает, в чем проблема то?

otvertka07

> теперь при вызове c->Init (data) мне нужно, чтобы использовался его IsValid

ну бля, это как раз и есть зависимость, значит IsValid должен быть виртуальным

alexkravchuk

> ну круто, и чо? фукция integr все пиздато считает, в чем проблема то?
В том то и проблема, что ничего она не считает из-за "static virtual"

a10063

это как раз и есть зависимость, значит IsValid должен быть виртуальным
это с самого начала ясно
ясно и то, что IsValid не зависит от объекта...
вот и virtual static

otvertka07

ну как же не зависит, если ты говоришь, что для C он у тебя должен свой быть?

a10063

A a = new B;
все время впечатление, что производится срезка а это, наверное, сишарп
a.Move =(полиморфизм)=> B.Move =(вызов базового класса)=> A.Move =(вызов)=> A.Paint =(полиморфизм)=> B.Paint =(вызов базового класса)=> A.Paint
a.Paint =(полиморфизм)=> B.Paint =(вызов базового класса)=> A.Paint
То как только они становятся статическими, первая цепочка уже работает не так, а вторая - всё ещё так.
пример оторван от интерфейса и от жизни, имхо. функции типа сдвинуть или нарисовать уж никак не статические. поэтому пример не понял

a10063

свой, но "C" - это класс, а от объекта "c" не зависит

otvertka07

а функция integr должны быть описана в другом классе, class Calc_my_integr

otvertka07

класс описывает поведение объекта - экземпляра класса
у объекта c, экземпляра класса C должно быть особое поведение, это и значит, что оно описывается его виртуальными методами, в данном случае IsValid

zzzzzzzzzzz

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

alexkravchuk

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

a10063

я уже сделал const и virtual-static walkaround, правда мне не очень нравится
радость статика - в строгости а значит в возможно лучшей оптимизации

otvertka07

короче, изучать ООП на примере C++ - это неблагодарное занятие, пишите на шарпе, яве, или любом другом правильном яп

alexkravchuk

Кстати, проясни для несведующих - что в Яве/Шарпе используется вместо C++ Templates?

kokoc88

В Джаве темплейтов как таковых нет. В последней версии там ввели некоторое подобие, дженерики. Раньше этого не было, поэтому шаблонный тип реализовал определённые интерфейсы.

a10063

класс описывает поведение объекта - экземпляра класса
у объекта c, экземпляра класса C должно быть особое поведение, это и значит, что оно описывается его виртуальными методами, в данном случае IsValid
это понятно
но мне нужно использовать эту функцию и без объекта... что без статика не получится

otvertka07

да они вообще нахер не нужны в реальной жизни, шаблоны эти

otvertka07

значит тебе надо два метода, один статический, который ты вызываешь из виртуальных

a10063

короче, изучать ООП на примере C++ - это неблагодарное занятие, пишите на шарпе, яве, или любом другом правильном яп
к сожалению, нормальных реализаций известных "правильных яп" не видел
я многого не знаю, но (подчеркиваю) наслышан, что ява - ужасно тормозная штука, а шарп - это вообще промоушн мокрософта, сырой и есть только кривые свободные поделки (какой-то моно, что-ли); он вообще открытый по спецификации?

alexkravchuk

Ну как знать, как знать... Получается, что есть три главных плюса Явы по стравнению с C++: 1) так нельзя использовать указатели; 2) там нельзя использовать goto; 3) там нельзя использовать шаблоны.
А вообще, в C++ изначально тоже ведь развивались объектные библиотеки, у Borland в версии 3-4 была известная Object Based Class Library, которая в пятой версии была окончательно вытеснена STL. Наверное всё же потому, что STL удобнее и быстрее... Из-за всего этого и трудно сменить C++ на Java/C#.

zzzzzzzzzzz

Экономия при подъеме RTTI весьма сомнительная

kokoc88

Я же написал, что в Джаве есть подобие шаблонов: дженерики. Некая модель, которая проверяется на этапе компиляции. Что без шаблонов очень хорошо живётся и они в реальной жизни не нужны - это, конечно, не так. Без них не очень хорошо: и в ненужные моменты в рантайме могут вылетать исключения, и код солидно обрастает try/catch блоками.

kokoc88

ява - ужасно тормозная штука, а шарп - это вообще промоушн мокрософта, сырой и есть только кривые свободные поделки
Джава не тормозная. Тормозные там только GUI библиотеки. В остальном... Надо просто знать, как правильно на ней писать.
Шарп уже давно не сырой. И есть его реализация от Майкрософт. Другое дело, что эта реализация только для винды.

a10063

значит тебе надо два метода, один статический, который ты вызываешь из виртуальных
увы, пришлось сделать именно так
но это не гармонично

kokoc88

увы, пришлось сделать именно так
но это не гармонично
Ну сам посуди, что ты предлагаешь? Ты пишешь об увеличении скорости работы за счёт применения статических функций. И при этом предлагаешь вызывать их через vtable. Ты выбери что-то одно: либо тебе быстро вызывается си-подобная функция, либо компилятор лазит по vtable. Вообще, я знаю минимум трёх ООП жлобов, которые за идею применения статических функций в таком случае просто бы тебя съели.

a10063

Джава не тормозная. Тормозные там только GUI библиотеки. В остальном... Надо просто знать, как правильно на ней писать.
если я правильно понимаю, чтобы хорошо писать на яве, нужно угадывать, какой С-код стоит за вызовами используемых средств, чтобы вышло оптимальнее...
Шарп уже давно не сырой. И есть его реализация от Майкрософт. Другое дело, что эта реализация только для винды.
значит код даже потенциально не переносим... ужас

bleyman

>> пример оторван от интерфейса и от жизни, имхо. функции типа сдвинуть или нарисовать уж никак не статические. поэтому пример не понял
Объясняю словами. Вот ты пишешь большую прогу на языке, позволяющем несимметричные вызовы - когда статический метод динамически биндится по объекту (кстати, практически никакого выигрыша в производительности не будет, отсутствие передачи лишнего параметра практически не роляет, одна инструкция mov, хуле).
И ты пишешь какой-нибудь статический метод, который предназначен именно для такого вызова, типа с понтом, что вызов должен спускаться вниз по иерархии объектов.
Во-первых, очень велика вероятность ошибиться и вызвать его именно статически.
Во-вторых, ты (или кто-нибудь другой, кто будет писать код на основе твоего) сделает ещё один такой же статический виртуальный метод, который будет вызывать твой. При этом без поллитры нифига не разберёшься, как именно происходит вызов.

kokoc88

если я правильно понимаю, чтобы хорошо писать на яве, нужно угадывать, какой С-код стоит за вызовами используемых средств, чтобы вышло оптимальнее...
Нет, не нужно. Нужно понимать, что такое язык с GC, как создавать поменьше объектов, какие вещи работают принципиально быстрее. Я тебе скажу, что есть очень много задач, в которых за пять минут в лоб написанный код на Джаве или Шарпе обгонит код на С++. До тех пор, пока ты не потратишь на решение той же проблемы на С++ 4-5 часов.
 
значит код даже потенциально не переносим... ужас
Код на Шарпе _потенциально_ вполне переносим. Опять же, С++ не является самым хорошим выбором для переносимости.

a10063

Ну сам посуди, что ты предлагаешь? Ты пишешь об увеличении скорости работы за счёт применения статических функций. И при этом предлагаешь вызывать их через vtable. Ты выбери что-то одно: либо тебе быстро вызывается си-подобная функция, либо компилятор лазит по vtable.
я предлагаю, чтобы компилятор за меня решил как оптимальнее сделать, раз мне нужны оба свойства
думаю, текущий обход гораздо менее оптимален
вообще, оптимизация у меня на 2-м месте
главное - понятный код, имхо
мне статика в моем случае понадобилась, когда я, уже имея виртуальную IsValid, понял, что она не опирается на данные и что мне нужно ее использовать отдельно от объекта
Вообще, я знаю минимум трёх ООП жлобов, которые за идею применения статических функций в таком случае просто бы тебя съели.

kokoc88

мне статика в моем случае понадобилась, когда я, уже имея виртуальную IsValid, понял, что она не опирается на данные и что мне нужно ее использовать отдельно от объекта
Нонсенс. Если у тебя IsValid разная для разных объектов, то это автоматически значит, что "ее использовать отдельно от объекта" нельзя. Если она у тебя одна для всех объектов, тогда пихай её в базовый класс. А если функция у тебя "пассивная", то объяви её как const.

bleyman

>> значит код даже потенциально не переносим... ужас
Да нет, уже очень давно есть оформленный стандарт, и уже где-то год как релизнулась стабильная версия Mono (это типа под никсы в которой в полном объёме есть ASP, и когда я когда-то давно смотрел, чем они занимались, они радостно переходили на C# 2.0, встраивали поддержку винформ и осваивали MSBuild.

a10063

И ты пишешь какой-нибудь статический метод, который предназначен именно для такого вызова, типа с понтом, что вызов должен спускаться вниз по иерархии объектов.
Во-первых, очень велика вероятность ошибиться и вызвать его именно статически.
Во-вторых, ты (или кто-нибудь другой, кто будет писать код на основе твоего) сделает ещё один такой же статический виртуальный метод, который будет вызывать твой. При этом без поллитры нифига не разберёшься, как именно происходит вызов.
возможно
дело в том, что я расцениваю static почти как const - просто некий ограничитель внутрянки, который расширяет твои возможности по использованию
иногда слишком большое расширение возможностей приводит к путанице, здесь я полностью согласен

a10063

Нонсенс. Если у тебя IsValid разная для разных объектов, то это автоматически значит, что "ее использовать отдельно от объекта" нельзя. Если она у тебя одна для всех объектов, тогда пихай её в базовый класс. А если функция у тебя "пассивная", то объяви её как const.
функция IsValid зависит только от дочернего класса, но не от объекта класса
и иногда их надо использовать просто как глобальные функции (ну, в namespace, конечно)

kokoc88

я расцениваю static почти как const - просто некий ограничитель внутрянки
Это совсем неправильно. Если const значит, что у тебя есть прямой (через this) доступ к членам класса, но ты их не модифицируешь; то static значит, что доступ к членам класса может быть только косвенный (передать объект вручную но при этом ты можешь изменять члены класса. И большая часть программистов в жизни не подумает, что под static ты понимал const.

a10063

Да нет, уже очень давно есть оформленный стандарт, и уже где-то год как релизнулась стабильная версия Mono (это типа под никсы в которой в полном объёме есть ASP, и когда я когда-то давно смотрел, чем они занимались, они радостно переходили на C# 2.0, встраивали поддержку винформ и осваивали MSBuild.
хорошие новости
все, что я раньше слышал/читал про моно было не таким радужным

zzzzzzzzzzz

мне нужно ее использовать отдельно от объекта
Хмм. Заведи обертку chk::IsValid(const type_info &)

bleyman

>>дело в том, что я расцениваю static почти как const - просто некий ограничитель внутрянки, который расширяет твои возможности по использованию
Так вот нет. Создатели плюсов (равно как шарпа и жавы) назвали статическими те функции, которые ВООБЩЕ не привязаны к объектам. И ты очень неправ, что понимаешь слово static не так, как разработчики языка, разработчики компиляторов и вообще основная масса программеров на плюсах

kokoc88

функция IsValid зависит только от дочернего класса, но не от объекта класса
Если у тебя две разных IsValid у двух разных дочерних классов, то "ее использовать отдельно от объекта" нельзя.
PS И вообще непонятно, в какой задаче удобно иметь функцию, которая вызывается как без объекта, так и с объектом.

a10063

Это совсем неправильно. Если const значит, что у тебя есть прямой (через this) доступ к членам класса, но ты их не модифицируешь; то static значит, что доступ к членам класса может быть только косвенный (передать объект вручную но при этом ты можешь изменять члены класса. И большая часть программистов в жизни не подумает, что под static ты понимал const.
что значит "совсем"?
различие я понимаю, но ты ведь не написал, для чего это используется...
я ведь могу опустить static и const - ничего плохого не будет, если я не использовал этих "подсказок" - в этом я вижу сходство
спецификаторы позволяют шире использовать методы, но ставят ограничения на код

a10063

Так вот нет. Создатели плюсов (равно как шарпа и жавы) назвали статическими те функции, которые ВООБЩЕ не привязаны к объектам. И ты очень неправ, что понимаешь слово static не так, как разработчики языка, разработчики компиляторов и вообще основная масса программеров на плюсах
так и не понял, что именно я понимаю неправильно?

kokoc88

что значит "совсем"?
различие я понимаю, но ты ведь не написал, для чего это используется...
я ведь могу опустить static и const - ничего плохого не будет, если я не использовал этих "подсказок" - в этом я вижу сходство
спецификаторы позволяют шире использовать методы, но ставят ограничения на код
Даже в смысле использования совсем не верно. Модификатор const пишут, когда у тебя функция не изменяет внутренности объекта. Это чтобы программист понял, что GetSize у динамического массива не сотрёт его содержимое, например.
Модификатор static ставят тогда, когда функция никоим образом не привязана к поведению объекта. При этом она может получать объект извне и модифицировать его на своё усмотрение. Типичный пример для таких функций: создание экземпляров класса.

kokoc88

так и не понял, что именно я понимаю неправильно?
Ты пытаешься использовать статическую функцию в том случае, когда её работа зависит от объекта.

a10063

Если у тебя две разных IsValid у двух разных дочерних классов, то "ее использовать отдельно от объекта" нельзя.
можно. я предлагаю использовать со спецификатором класса (это дает статик) или резолвить в теле метода родительского класса (это вирчуал) - вот и все (т.е. в зависимости от применения)
фишка в том, что статик и вирчуал - вещи абсолютно параллельные!
И вообще непонятно, в какой задаче удобно иметь функцию, которая вызывается как без объекта, так и с объектом.
она вызывается с объектом только для определения класса, из которого эту функцию вызывать

bleyman

Блиа, тебе ещё в самом начале треда Ахтох нопейсал, что статические методы не привязаны к объектам, а привязаны к классам, и ООП-фишки типа полиморфизма на них просто не действуют. Так это понимают вообще ВСЕ. Ты этого не понимаешь.

kokoc88

можно. я предлагаю использовать со спецификатором класса (это дает статик) или резолвить в теле метода родительского класса (это вирчуал) - вот и все (т.е. в зависимости от применения)
фишка в том, что статик и вирчуал - вещи абсолютно параллельные!
Фишка в том, что статик и виртуал вещи абсолютно перпендикулярные. Виртуальная функция опирается на объект, статическая - нет.

a10063

Даже в смысле использования совсем не верно. Модификатор const пишут, когда у тебя функция не изменяет внутренности объекта. Это чтобы программист понял, что GetSize у динамического массива не сотрёт его содержимое, например.
Модификатор static ставят тогда, когда функция никоим образом не привязана к поведению объекта. При этом она может получать объект извне и модифицировать его на своё усмотрение. Типичный пример для таких функций: создание экземпляров класса.
я вижу главное применение этих двух в том, чтобы компилятор понял что-то, а потом уж программист
если бы конст и статик не давали преимуществ (вызов для константного объекта и без объекта то их попросту ленились бы использовать

kokoc88

я вижу главное применение этих двух в том, чтобы компилятор понял что-то, а потом уж программист
если бы конст и статик не давали преимуществ (вызов для константного объекта и без объекта то их попросту ленились бы использовать
Нет, ты опять недопонимаешь. Есть необходимость: например, создание первого экземпляра главного класса программы происходит в статической функции. Или если тебе нужно контролировать процесс создания классов: можно объявить конструктор протектедом, и позволять создавать класс только через вызов статической функции.

a10063

Блиа, тебе ещё в самом начале треда Ахтох нопейсал, что статические методы не привязаны к объектам, а привязаны к классам, и ООП-фишки типа полиморфизма на них просто не действуют. Так это понимают вообще ВСЕ. Ты этого не понимаешь.
я понимаю, что так есть
не понимаю почему?
если уж разрешили использовать this->static_method, так вызывайте правильный метод!

alexkravchuk

я вижу главное применение этих двух в том, чтобы компилятор понял что-то, а потом уж программист
если бы конст и статик не давали преимуществ (вызов для константного объекта и без объекта то их попросту ленились бы использовать
Здесь ты зря так. Static - даёт преимущества тем, что не передаётся указатель на объект, хотя преимущество здесь - невелико обычно. Декларативное - тоже минимально, впрочем.
Const же - исключительно декларативен, для программиста, компилятор разве что не даст сделать явной ошибки. Но в другом функции с const и обычное - ничем не отличаются.

a10063

Нет, ты опять недопонимаешь. Есть необходимость: например, создание первого экземпляра главного класса программы происходит в статической функции. Или если тебе нужно контролировать процесс создания классов: можно объявить конструктор протектедом, и позволять создавать класс только через вызов статической функции.
ну так это все подходит под то, что я написал
есть необходимость - люди ставят спецификаторы и все
что же я недопонимаю?

kokoc88

я вижу главное применение этих двух в том, чтобы компилятор понял что-то, а потом уж программист
если бы конст и статик не давали преимуществ (вызов для константного объекта и без объекта то их попросту ленились бы использовать
ну так это все подходит под то, что я написал
есть необходимость - люди ставят спецификаторы и все
что же я недопонимаю
Так ты определись: необходимость для программиста или чтобы комплятор что-то понял. Не ленятся использовать как правило static именно из-за того, что он не привязан к объекту. И каково бы ни было описание вызова статического метода, он (метод) всё равно не связан с объектом.

a10063

Static - даёт преимущества тем, что не передаётся указатель на объект, хотя преимущество здесь - невелико обычно. Декларативное - тоже минимально, впрочем.
разве я не о том же написал: "преимуществ (вызов ... без объекта)"?
Const же - исключительно декларативен, для программиста, компилятор разве что не даст сделать явной ошибки. Но в другом функции с const и обычное - ничем не отличаются.
ага. именно поэтому я удивлялся сообщениям компилятора на ранней стадии изучения плюсов, когда он не давал мне вызвать не const функцию на константном объекте
ошибка хоть и явная, ее надо исключать

alexkravchuk

Нет, я не понимаю, о чём мы говорим... Вызов статической функции происходит без объекта, в то время как вызов обычной - с передачей указателя на уже созданный объект. В этом и есть главный плюс статической функции. Тут до меня дошло, в чём проблема с витруальной статической функцией (я тормозил): Смотри. Есть объект, уже созданный - принципиально то, что указатель на таблицу виртуальных функций - это один из элементов этого объекта! То есть, не создав объект, мы не можем узнать, где находится таблица виртуальных функций, и из-за этого не можем вызвать эту самую статическую виртуальную функцию без объекта. То есть, теоретически это дело можно обойти, но дополнительная работа - слишком большая, и оно того не стоит.

a10063

Так ты определись: необходимость для программиста или чтобы комплятор что-то понял.
понимание компилятора влечет запреты и необходимость для программиста

kokoc88

Господи, ты уже в третий раз повторил то, что сначала было сказано Ахтохом, затем Fj и мной. Ладно, более детально это уже не разжевать.

kokoc88

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

a10063

Тут до меня дошло, в чём проблема с витруальной статической функцией (я тормозил): Смотри. Есть объект, уже созданный - принципиально то, что указатель на таблицу виртуальных функций - это один из элементов этого объекта! То есть, не создав объект, мы не можем узнать, где находится таблица виртуальных функций, и из-за этого не можем вызвать эту самую статическую виртуальную функцию без объекта. То есть, теоретически это дело можно обойти, но дополнительная работа - слишком большая, и оно того не стоит.
это понятно, но я ведь делаю не так
у меня фактически два применения функции, не связанных друг с другом
1. отдельно от всего - тогда C::IsValid - вопросов нет
2. внутри функции род. класса P, т.е. this->IsValid - т.е. уже объект есть (this) и у него можно посмотреть таблицу

kokoc88

это понятно, но я ведь делаю не так
у меня фактически два применения функции, не связанных друг с другом
1. отдельно от всего - тогда C::IsValid - вопросов нет
2. внутри функции род. класса P, т.е. this->IsValid - т.е. уже объект есть (this) и у него можно посмотреть таблицу
Ёлы палы. Тебе уже сколько раз сказали? Ну нету привязки к объекту при вызове this->IsValid если IsValid статическая. Понимаешь? В этом и есть смысл static. Джава или Шарп не дадут тебе так написать вообще, и это правильно. Жаль, что в С++ нету ограничения, оно сбивает с толку новичков.
Ты же предлагаешь фактически, чтобы в некоторых случаях static функции опирались на объект. В этом и есть полное противоречие.

a10063

Причину и следствие местами не меняй. Это программисту нужно какое-то поведение. И он говорит компилятору, каким это поведение должно быть.
но предварительно программисту не дал компилятор что-то сделать и он полез менять спецификаторы
так что я не меняю, просто у тебя вторая часть цепочки

bleyman

Ты не понял. Чувак говорит о том, что когда у нас уже ЕСТЬ объект, можно засунуть ему в vmt указатели на статические методы тоже. И обрабатывать вызовы с использованием полиморфизма, а потом просто не передавать указатель на объект.
Да, это можно сделать.
Но код в результате превратится в спагетти.

kokoc88

Да мы это всё уже давно поняли. Пытаемся ему втолковать, в чём сакральный смысл слова static.

a10063

Ну нету привязки к объекту при вызове this->IsValid если IsValid статическая. Понимаешь? В этом и есть смысл static.
Понимаю. Ну вот ты, здравый человек, когда тебе напишут this->IsValid ты какую из объявленных статических функций вызовешь?
Жаль, что в С++ нету ограничения, оно сбивает с толку новичков.
+1

alexkravchuk

> 2. внутри функции род. класса P, т.е. this->IsValid - т.е. уже объект есть (this) и у него можно посмотреть таблицу
Можно... Но всё же, это лишняя работа, некоторая дополнительная путаница... То есть "овчинка не стоит выделки", я так думаю. Я могу описать ситуации, когда подобное будет удобнее своей наглядностью...

kokoc88

Понимаю. Ну вот ты, здравый человек, когда тебе напишут this->IsValid ты какую из объявленных статических функций вызовешь?
Я буду считать, что вызывают нестатическую функцию и очень удивлюсь, если она окажется статической. После чего я отфакторю всё дерево классов, связанных с этой бредятиной и сделаю cvs commit.

a10063

Чувак говорит о том, что когда у нас уже ЕСТЬ объект, можно засунуть ему в vmt указатели на статические методы тоже. И обрабатывать вызовы с использованием полиморфизма, а потом просто не передавать указатель на объект.
спасибо. хоть кто-то меня понял если я пишу virtual static, наверное, я этого хочу!
кстати, написав обход я именно это и сделал, только функций две
Да, это можно сделать.
Но код в результате превратится в спагетти.
не доказано.

kokoc88

если я пишу virtual static
...то всё ещё не понимаю, что такое virtual и что такое static.

a10063

ладно. не злись!
спасибо всем за обсуждение! считаю тему закрытой...
открывается конкурс на лучшее обходное решение

alexkravchuk

> открывается конкурс на лучшее обходное решение
Завести в качестве public-переменной указатель на функцию, который присваивать - в конструкторе... Хотя традиционный подход (правда для несколько иных ситуаций, чем ты описываешь - это уже ближе к моему примеру) - просто завести виртуальную функцию, которая будет возвращать указатель на функцию. Типа свой маленький COM.

enochka1145

Эх, всё уже сказано до нас... до меня, то есть.
Остаётся подвести итог. Есть три случая:
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);
     }
});
    }
}

rosali

увы, пришлось сделать именно так
но это не гармонично
писать функцию Init вместо конструктора -- вот это негармонично. А все эти твои static virtual...
PS. Я фигею, 100 постов на такую тему!..

a10063

Завести в качестве public-переменной указатель на функцию, который присваивать - в конструкторе... Хотя традиционный подход (правда для несколько иных ситуаций, чем ты описываешь - это уже ближе к моему примеру) - просто завести виртуальную функцию, которая будет возвращать указатель на функцию. Типа свой маленький COM.
можно и так
в любом случае нужно заботиться о лишнем при описании дочернего класса, явно указывать - "ты, пожалуйста, используй эту статическую функцию, чтобы выполнялся полиморфизм при вызове от объекта" - как ни оберни это
я так до сих пор и не понял, почему мне нужно извращаться в моем случае, дублировать функцию или использовать указатель на функцию (что почти одно и то же)
ведь противоречий не возникает при использовании virtual+static. запретили бы тогда вызывать от объекта - и дело с концом... зачем нужна запись obj->static_function при отсутствии virtual-static функций не понятно...

a10063

писать функцию Init вместо конструктора -- вот это негармонично.
естественно у меня в реальном примере не init...
назови ее xxx, так понятнее? вижу, ты не умеешь концентрироваться на проблеме

a10063

Для выбора одного из этих трёх (непересекающихся, заметь) вариантов машине нужно как минимум 2 бита. Однако 2 бита могут быть в четырёх состояниях, и уж прости, что это четвёртое, о котором ты говоришь, запрещено. Так вышло.
хорошее сравнение про биты, именно так себе и представляю
цель треда была - выяснить, почему так вышло и связано это или нет с конкретными реализациями компиляторов

enochka1145

ОК.
Ещё напрашивается аналогия с far/near, cdecl/pascal, auto/static, signed/unsigned и т. д.
Представляешь, как было бы удобно - скажем, переменная создаётся в стеке (auto но помнит (static) своё значение...
А всего-то надо было бы написать:
auto static int i;

Dasar

в C++ то, что ты хочешь - делается так:

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
}

}

a10063

wow, мне понравилась идея сделать через шаблон, чтобы не вспоминать
только так нельзя перегружать функции:
    virtual void IsValid(int data)
{
T::IsValid(data);
}
static void IsValid(int data){}

но идея ясна
минус только в том, что шаблоны сложнее отлаживать

Flack_bfsp

ведь противоречий не возникает при использовании virtual+static
Лол! Ты вообще читать умеешь? Тебе же разжевали дальше некуда, почему возникают противоречия.

a10063

Лол! Ты вообще читать умеешь? Тебе же разжевали дальше некуда, почему возникают противоречия.
удивишься, но умею! мне разжевали определения, которые я и так знал. никто не привел примера, где неясно как использовать virtual static функцию. собственно, мне его и хотелось получить, когда я писал первый пост

Flack_bfsp

Её никак нельзя использовать, потому что vtable - часть объекта, а статические функции с объектами не связаны.
Какие тебе ещё объяснения нужны?
Если бы всё было так, как ты и хотел, то есть статики лежали в каком-то особенном месте vtable, то менялась бы сама семантика статических функций - они бы были связаны с объектами. То есть виртуальную функцию никакими ухищрениями нельзя сделать статической, даже путём изменения стандарта.

Dasar

> никто не привел примера, где неясно как использовать virtual static функцию

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)?

alexkravchuk

Её никак нельзя использовать, потому что vtable - часть объекта, а статические функции с объектами не связаны.
Какие тебе ещё объяснения нужны?
Если бы всё было так, как ты и хотел, то есть статики лежали в каком-то особенном месте vtable, то менялась бы сама семантика статических функций - они бы были связаны с объектами. То есть виртуальную функцию никакими ухищрениями нельзя сделать статической, даже путём изменения стандарта.
Перечитай тред, если осилишь... Все эти моменты уже обсудили, и не один раз.
Если кратно - отличие статической функции от простой функции-члена (не важно, виртуальная она или нет) - в том, что в обычной функции неявно передаётся указатель на объект. Поэтому простую функцию без объекта вызвать принципиально невозможно. Допустим, у нас есть виртуальная функция член - тогда её проблема состоит только в том, что не понятно, как её найти без таблицы указателей на виртуальные функции, но если знать, где она лежит - то её можно вызвать и без объекта. То есть, это тем не менее - полноценная статическая функция, просто появляются некоторые дополнительные проблемы с нахождением указателя на неё. То есть, подобное вполне реально реализовать, однако проблема, как мне сейчас кажется - что просто было лень заморачиваться подобными нетривиальными конструкциями, которые, при этом, нужны достаточно редко... Тем более, что можно было много других вещей доработать, если бы большое желание было, вместо этого.

enochka1145

По-моему, гражданин просто ж0стко прикалывается. Сколько раз сказано - переопределять статические функции в производных классах никто не запрещает, ты только пальцем покажи, какую именно (какого именно класса) статический метод с этим именем ты хочешь вызвать; если же на этапе компиляции этого сказать нельзя, а надо смотреть, какого конкретно класса данный объект, значит, нужен this (ну, чтобы как-то обозначить этот конкретный объект). А this и static - вещи взаимоисключающие. Чё не понятно-то?

Chupa

у тебя логическая ошибка

enochka1145

Ошибка ты хотел сказать?

alexkravchuk

> Чё не понятно-то?
Вот это вот не понятно:
> А this и static - вещи взаимоисключающие.
Что такое static (применительно к Ф-Ч)? В случае, если функция не виртуальная, а обычная Ф-Ч - то этоо такая функция, которая не получает указателя на объект в качестве параметров. Теперь добавляем слово virtual - по определению и смыслу этого слова, для того, чтобы обратиться к функции, необходимо посмотреть на таблицу виртуальных функций соответствующего объекта.
То есть:
Механизм виртуальных функций срабатывает ДО запуска кода функции, его суть, смысл заключается в том, чтобы получить указатель на функцию по объекту - после того, как этот указатель найден, виртуальную функцию нельзя отличить от обычной, они на следующем этапе будут ИДЕНТИЧНЫМИ.
Механизм статических функций срабатывает во время запуска функции (при передачи параметров в стек и по ходу всего исполнения функции, так как компилятор внутри функции не имеет указателя на объект.
Таким образом, слова virtual и static - не противоречат друг другу! Да, virtual накладывает некоторые ограничения и вносит дополнительную путаницу - но явных противоречий здесь нет! Это не антонимы, это просто разные механизмы разного назначения.

otvertka07



Или если тебе нужно контролировать процесс создания классов: можно объявить конструктор протектедом, и позволять создавать класс только через вызов статической функции.

а как запрещать создание не через конструктор? в java и с++

enochka1145

// Механизм виртуальных функций срабатывает ДО запуска кода функции, его суть, смысл заключается в том, чтобы получить указатель на функцию по __объекту__ - после того,
По объекту, но не по this? Как это?
Видишь ли перед вызовом метода указатель на данный объект можно
- либо поместить в стек
- либо не помещать в стек
Если функция static, она указатель в стек не помещает. Если нет - помещает, даже самая что ни на есть virtual. Как совместить эти два действия, я не понимаю.

alexkravchuk

> По объекту, но не по this? Как это?
> Если функция 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 ему не нужно! Да, чтобы вызвать функцию - указатель на созданный объект нужен, но только потому, что иначе нельзя установить, где лежит указатель на функцию. После того, как указатель получен - знать об объекте ничего не нужно.

enochka1145

ОК. Убедил.

a10063


Какой из методов, ты хочешь, чтобы в каждом из вариантов был вызван (A.IsValid или B.IsValid)?
1 - A
2 - B
3 - B
в общем, как при полиморфизме
идея такова для virtual static (раз разрешили зачем-то использовать запись obj->stat_func)
если используется класс::функция - то понятно какой код исполнять еще на этапе компиляции
если написано объект->функция, то, все-таки, хотелось бы видеть полиморфные свойства
как такую идею реализовать - хорошо написал
на данный момент запись obj->stat_func только вводит в заблуждение и может привести к ошибкам
подозреваю, что virtual static запретили, чтобы тем, кто привык, что про статику все известно на этапе компиляции, было удобнее
вообще, имхо, статик для метода класса должен означать лишь то, что данные объекта не используется, даже если он участвует в вызове - в общем-то у Бьерна именно так и написано

rosali

никто не привел примера, где неясно как использовать virtual static функцию
Логично что из одной static virtual функции может вызываться другая static virtual функция? И она должна вызывать "правильная", так ведь? Поэтому не передавать указатель на объект нельзя, а значит можно без ущерба с точки зрения оптимизации слово static стереть.

alexkravchuk

Логично что из одной static virtual функции может вызываться другая static virtual функция? И она должна вызывать "правильная", так ведь? Поэтому не передавать указатель на объект нельзя, а значит можно без ущерба с точки зрения оптимизации слово static стереть.
Нет, логичным было бы, что в силу этого из такой виртуальной статической функции нельзя было бы вызвать другую виртуальную функцию (в том числе статическую). Да, дополнительное ограничение, но не принципиальное... То есть понятно, что из-за подобных ограничений полезность подобных функций уменьшается, но это не значит, что они совсем уж бесполезны... Просто нерациональны.

a10063

Нет, логичным было бы, что в силу этого из такой виртуальной статической функции нельзя было бы вызвать другую виртуальную функцию (в том числе статическую). Да, дополнительное ограничение, но не принципиальное... То есть понятно, что из-за подобных ограничений полезность подобных функций уменьшается, но это не значит, что они совсем уж бесполезны... Просто нерациональны.
достаточно использовать для вызова вирчуал-статик методов только 2 записи: класс::функция, объект->функция, а остальные считать ошибочными.
т.к. в статической функции нельзя использовать this, привязка к объекту нам не нужна внутри такой функции и все вызовы в-с функций внутри будут однозначно определены
в этом случае полезность остается прежней

Flack_bfsp

Перечитай тред, если осилишь... Все эти моменты уже обсудили, и не один раз.
Чуве, я в курсе, что такое статик и как оно работает. Отвечать, не прочитав всего треда, тоже не имею привычки. Поэтому не надо рассказывать мне вкратце, что было раньше. Я это и сам сделал своим постом.

Flack_bfsp

где хранится сама таблица виртуальных функций - не помню, вроде она одна на весь класс, а не на кажный объект, но могу ошибаться, и это не принципиально
Ты ошибаешься, она на каждый объект, и это принципиально. То есть доступа к виртуальной функции нельзя получить без объекта. Запись вида имя_класса::имя_виртуальной_статической_функции не имеет смысла. Или ты предлагаешь ещё и имена статических функций хранить в двух местах?

Ivan8209

> Ты ошибаешься, она на каждый объект, и это принципиально.
То есть, приплюснутые насильники нагло лгут,
когда говорят про сильную типизацию.
---
...Я работаю антинаучным аферистом...

Chupa

> Ты ошибаешься, она на каждый объект, и это принципиально.
Неправда. Таблица общая на все объекты класса. В самих объектах хранится только указатель на неё.
> Запись вида имя_класса::имя_виртуальной_статической_функции не имеет смысла.
Неправда. Компилятору известны адреса функций, больше здесь ничего не требуется.

enochka1145

"В ваш дурдом уже провели интернет?"
Почему насильники? Куда делись боевики? На другую траву перешёл? Или сменил психиатра?

Ivan8209

Боевиков нету, есть насильники и сантехники.
---
...Я работаю антинаучным аферистом...

Dasar

> Что должен делать КОМПИЛЯТОР - считать неявную переменную aa.v_ptr (как и раньше подставить call - вызов функции aa.v_ptr[1], но при этом в стек запихивать this ему не нужно!
Тогда получится, что из такого метода - мы не сможем вызывать другие виртуальные методы, в том числе - даже virtual static, т.е. решение получается незамкнутое.

rosali

 
мы не сможем вызывать другие виртуальные методы, в том числе - даже virtual static
Я им уже говорил. , что в этом их "исчислении" логично будет запретить вызывать из static (даже virtual) что-то зависящее от объекта, в частности, virtual (даже static). Вот такой замкнутый круг хехе

Chupa

Это всё абстрактные рассуждения, которые без привязки к конкретным задачам бесполезны.
Что мешает вызвать virtual static метод? Отсутствие объекта не проблема, если известен нужный класс (типичный случай - вызов метода предка). Если же класс не известен и никакого объекта нет, то проблема не в методе, а в постановке задачи, где требуется такой вызов непонятно зачем совершить.

Chupa

> что-то зависящее от объекта, в частности, virtual (даже static).
Ошибочка вышла: virtual static зависит не от объекта, а только от его типа. Разница принципиальная.

enochka1145

// Это всё абстрактные рассуждения, которые без привязки к конкретным задачам бесполезны.
Ну придумай сам конкретную задачу. Например, затасканную иерархию форм. Пусть статическая виртуальная функция пишет: "Я прямоугольник" или "Я круг".
// Что мешает вызвать virtual static метод? Отсутствие объекта не проблема, если известен нужный класс
Если известен (при компиляции) нужный класс, то мы пишем:
НужныйКласс::нужныйМетод(...);
. Если не изветен, то нужен this, причем именно this, а не какое-то производное знание вроде названия класса, так как мы тут же захотим вызывать другие виртуальные статические методы.

Chupa

> Если не изветен, то нужен this, причем именно this, а не какое-то производное знание вроде названия класса, так как мы тут же захотим вызывать другие виртуальные статические методы.
Не надо причину со следствием путать.
Правильный подход выглядит так: сначала ставится задача, потом определяются средства решения. Здесь почему-то упорно предлагается всё вывернуть наизнанку: сначала берётся метод, а потом под него подгоняется какая-то неудобная задача, причём даже не задача, а нечто с шапкозакидательской аргументацией ("так как мы тут же захотим ...").
Просто статические методы широко используются без всяких this, и это не является проблемой. virtual static отличается лишь в одном: его можно вызывать не только напрямую, но и через чью-нибудь VMT.
Мне сложно представить задачу, где понадобился бы virtual static, разве что какая-нибудь отладка или низкоуровневые извраты, но это совсем не значит, что такой механизм не имеет права на существование. Да, его возможности ограничены, но не более того.

Dasar

> Правильный подход выглядит так: сначала ставится задача, потом определяются средства решения.
В жизни используется много правильных подходов.
Это правильный - инженерный подход, когда сначала определяется что мы хотим решить, а потом - как.
Есть еще правильный - научный/теоретический подход, когда изучаются и определяются средства, а уже потом ищутся задачи, для решения которых мы эти средства можем использовать.

Ivan8209

> научный/теоретический подход, когда изучаются
> и определяются средства, а уже потом ищутся задачи
Сразу видно математика.
---
"Унивеpситет pазвивает все способности, в том числе глупость."
А. Чехов

Flack_bfsp

Кстати, в стандарте, раздел 10.3, пункт 7 как раз говорится о том, почему нельзя употреблять vitrual static.

Flack_bfsp

> Ты ошибаешься, она на каждый объект, и это принципиально.
Неправда. Таблица общая на все объекты класса. В самих объектах хранится только указатель на неё.
Ладно, сойдёмся на том, что в стандарте это не оговорено, и реализовано может быть и тем и другим способами.

Chupa

> в стандарте, раздел 10.3, пункт 7 как раз говорится о том, почему нельзя употреблять vitrual static
Стандарт приводит тоже самое рассуждение: если без объекта нельзя сделать вызов, то функция не может быть статической. С технической точки зрения утверждение неверно, что здесь уже подробно расписали. С точки зрения ООП - другой вопрос, наверное, есть какие-то грабли.
Поиск в гугле даёт ссылки на различные обсуждения данного вопроса, но разгребать всё это пока желания нет.

otvertka07

бля, понаписали тут, а на мой вопрос не ответили, как запретить не через конструктор экземпляр создавать? в c++ и java

zzzzzzzzzzz

Это, видимо, еще более жесткий каламбур?

otvertka07

вот к примеру у меня есть суперкласс C и дохрена потомков всяких, я создаю экземпляр с помощью конструктора:
C myObj = C::construct(myParm);
 
а внутри construct в зависимости от параметра создается экземпляр одного из потомков, ну и еще что-нибудь делается типа инициализации
 
как мне запретить вызов new для потомка не из конструктора?

kokoc88

Вчера ночью точно так же, как и ты, написал на С++. Приводить не стал по одной причине: для передачи указателя на класс куда-либо, придётся делать ещё один базовый класс для "template<class TType>class A". Что в общем-то выглядит менее красиво, чем виртуальная функция, вызывающая статическую.

kokoc88

Объявить конструкторы потомков protected/private, сделать базовый класс friend'ом.

otvertka07

это в C++? а в java как?

kokoc88

Объявить у дочерних классов конструкторы с доступом в пределах пакета.

enochka1145

А что поконкретнее ты хочешь? Вроде сделал свой класс final, и все свободны. Или не сделал final. Но тогда у тебя ещё 2 опции: public class или /* package */ class, как уже сказал .

enochka1145

// ...если без объекта нельзя сделать вызов, то функция не может быть статической. С технической точки зрения утверждение неверно, что здесь уже подробно расписали.
По-моему, один из нас идиот. Вроде все согласились, что можно не помещать в (или, скорее выталкивать из, для тех у кого есть только стек; ну как в Форте) стек this специально для virtual static метода. Но совсем без this не обойтись. А раз так, зачем делать вид, что его нет?
Когда ты это поймёшь?

Chupa

> По-моему, один из нас идиот.
Самокритично.
> Вроде все согласились, что можно не помещать в (или, скорее выталкивать из, для тех у кого есть только стек; ну как в Форте) стек this специально для virtual static метода.
Cогласились, я разве с этим спорю?
> Но совсем без this не обойтись.
Очень даже обойтись. virtual static можно использовать, как обычный static, что указывалось в этом треде очень много раз.
> А раз так, зачем делать вид, что его нет?
Не так.
> Когда ты это поймёшь?
В своей башке сначала порядок наведи.

enochka1145

Чем отличается
имя_класса::имя_виртуальной_статической_функции(...)
от имя_класса::имя_статической_функции(...) ?

Chupa

Ничем.

enochka1145

А зачем тогда слово "virtual"?

Chupa

Чтобы при вызове вида obj->static_virtual_method метод выбирался в зависимости от типа объекта, на который указывает obj в процессе выполнения кода.

enochka1145

obj->static_virtual_method
Как ты думаешь, что значит, "obj->" для процессора? Т.е., какими инструкциями ты бы это представил на ассемблере? Хоть на каком-нибудь: Intel, MSIL, JVM...

Ivan8209

А как ты думаешь, что значит, "const int" для процессора?
---
...Я работаю антинаучным аферистом...

Chupa

Само по себе ничего не значит. А вот для компилятора значит. В случае просто static метода, его адрес будет определён сразу по типу указателя и сгенерирован прямой вызов. От virtual static ожидается вызов через таблицу виртуальных методов объекта.

alexkravchuk

> obj->static_virtual_method
> Как ты думаешь, что значит, "obj->" для процессора?
Имеется в виду, что если присутствует такая запись, со ссылкой на объект - то значит сам объект существует, и из него можно извлечь указатель на таблицу виртуальных функций (тем же образом, как и извлекается указатель для обычных виртуальных функций). Если же конкретного объекта нет (например, хочется вызвать одну статическую функцию из другой то вызов можно производить лишь по записи вида class_name::static_virtual_method.

enochka1145

// От virtual static ожидается вызов через таблицу виртуальных методов объекта.
Минуя this?

Chupa

> Т.е., какими инструкциями ты бы это представил на ассемблере? Хоть на каком-нибудь: Intel, MSIL, JVM...
вот так (псевдокод):
объявления:

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

enochka1145

OK, спасибо.
А этот вот obj, который мелькает в ассемблерном коде, это часом не this, без которого, по твоим словам, можно обойтись?

Chupa

Для кого-то он, безусловно, this, в частности, для самого obj. Для куска кода, в котором делаются эти вызовы - совсем не обязательно.

zzzzzzzzzzz

Так ты под конструктором метод с именем construct понимаешь? Оригинально.
Конструктор (в терминологии C++) имеет те же модификаторы доступа, что и остальные методы, так что вопрос удивителен. Ответ, впрочем, дали.

enochka1145

ОК, спасибо, ясно.

otvertka07

а я с c++ не дружу что там есть уонструктор?

Olyalyau

Статические методы и переменные класса отличаются от обычных тем, что статические методы не принимают указатель на объект (экземпляр) класса в качестве первого (неявного) аргумента, а статические переменные не находятся в памяти объекта класса.
Виртуальные методы отличаются тем, что вызываются в соответствии с настоящим классом объекта, даже если обращение происходит через указатель на предка класса объекта. Для этого каждый объект с виртуальными методами содержит в качестве данных таблицу виртуальных методов и вызов происходит через эту таблицу (из таблицы берётся указатель на метод и делается косвенный вызов).
Таким образом, для того, чтобы метод был виртуальным, нужно чтобы указатель на этот метод был в любом объекте класса (внутри таблицы виртуальных функций). Статические функции не имеют доступа к объекту (так как не получают указатель на него в качестве аргумента а значит, не имеют доступа к таблице виртуальных методов, значит не могут быть виртуальными. Более того, обращение к статическим методам и переменным возможно и в случае отсутствия вообще объектов класса.
В принципе, можно сделать, чтобы статические методы были виртуальными, но это на мой взгляд не имеет практического смысла.

kokoc88

Ты бы перед своим постом написал "всё предыдущее ниасилил, многа букф".

otvertka07

Ivan8209

> статические методы не принимают указатель на объект
> даже если обращение происходит через указатель
> каждый объект [...] содержит в качестве данных таблицу виртуальных методов
> из таблицы берётся указатель
Ладно, это всё детали реализации, а семантически это как?
---
...Я работаю антинаучным аферистом...

enochka1145

Java:
class A {
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]);
}
}
На C++ с включённым RTTI должно быть что-то похожее.

zzzzzzzzzzz

Семантически выражение «virtual static» противоречиво.

kokoc88

Теперь скажи, это выполнится быстрее виртуальных функций, которые вызывают статические? Или, может быть, это более читаемо/лаконично? На последний вопрос ответ точно отрицательный, т.к. все джава среды очень хорошо позволяют прыгать по методам.
На С++ подобное решение будет гораздо тяжелее.

enochka1145

Java. Мы не торопимся.
Проблемы людей, которые хотят сэкономить на push obj, продолжая копаться в таблице виртуальных функций, мне вообще не понять. Это был чисто теоретический изыск.

kokoc88

Java. Мы не торопимся.
А вот это очень и очень зря. Потому что из-за тонн тормозного Джава кода этот язык считают тормозным и убогим.

enochka1145

Это была шутка.
---
"I will use smilies every time I am joking. I will use smilies.."

SPARTAK3959

В Delphi есть "virtual static" функции - это называется virtual class function. Используются они не часто. Основной их смысл в том, что этим функциям вместо указателя на объект передается указатель на таблицу виртуальных методов (в частности из них можно вызывать другие class function и конструкторы, а обычные методы вызывать, разумеется, нельзя). В С++ их нет, потому что язык развивался по-другому и теперь уже сложно что-либо изменить.
Оставить комментарий
Имя или ник:
Комментарий: