Здравствуйте, MT, Вы писали:
MT>Но есть противоречивые ответы... MT>Поэтому уточните пожалуста — должен ли я определять чисто виртуальную функциу в производном классе, или можно не определять?
Если у тебя в классе есть чисто виртуальные функции, то класс является абстрактным; если в потомке абстрактного класса переопределены не все функции, являющиеся в классе-предке чисто виртуальными, то этот класс-потомок также абстрактный.
Класс не является абстрактным, только если в нем нет ни собственных ЧВФ, ни непереопределенных ЧВФ, "оставшихся в наследство" от класса-предка.
Виртуальная функция может быть переопределена в производном классе.
Чисто виртуальная функция должна быть переопределена в производном классе.
Чисто виртуальные функции обычно используют для создания интерфейсных классов.
Добавлю свои 2 копейки.
Ты можешь создать объект типа Shape, и не можешь — типа Shape2, потому как там чистая виртуальная функция. Получается абстрактный класс, как в Яве.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>Здравствуйте, Аноним, Вы писали:
LVV>Пардон-с!!! Где ж тут создание есть создание объекта абстракного класса?
В конструкторе абстрактного класса
class A
{
public:
virtual void pure() = 0;
void call_pure()
{
pure();
}
A() // vfptr = &A::vmt
{
pure(); // здесь - статический вызов;
// если функция не определена, линкер ошибет.
call_pure(); // здесь - динамический вызов;
// поскольку в VMT класса A неизвестно что, то будет undefined behaviour
// (вероятнее всего, там ссылка на функцию выброса исключения)
}
};
class B : public A
{
public:
virtual void pure() { ; }
B()
: A() // vfptr = &A::vmt
// vfptr = &B::vmt
{
pure();
call_pure(); // в данный момент используем уже VMT класса B
}
};
int main()
{
B b;
return 0;
}
Здравствуйте, MT, Вы писали:
MT>Чем отличается виртуальная функция от чистой виртуальной функции? MT>На примере двух классов:
MT>
MT>class Shape { virtual void draw(); }
// Здесь функция объявлена; предполагается, что ее определение - вне объявления класса.
// Отсутствие определения - вызовет ошибку линковки
// поскольку ссылка на функцию помещена в VMT этого класса
MT>class Shape2 { virtual void draw() = 0; }
// Эту функцию можно не определять (хотя можно и определить).
// А вот VMT с нуллевой ссылкой уже быть не может,
// поэтому создать экземпляр класса Shape2 невозможно
MT>
Наличие чисто виртуальной функции в твоем классе делает его абстрактным, объекты такого класса нельзя создавать, хотя можно объявить ссылки и указатели. Чисто виртуальная функция может иметь реализацию, только ее нельзя определить в классе.
Если умудриться вызвать такую функцию через ссылку или указатель, т.е. добиться вызова через втбл, то прога грохнется.
А еще очень много всего, но это лучше в книгах умных почитать или поиском пользоваться
Of course, the code must be complete enough to compile and link.
Re[2]: Virtual and Pure Virtual function
От:
Аноним
Дата:
25.08.03 13:33
Оценка:
Здравствуйте, Кодт, Вы писали:
MT>>
MT>>class Shape { virtual void draw(); }
К>// Здесь функция объявлена; предполагается, что ее определение - вне объявления класса.
К>// Отсутствие определения - вызовет ошибку линковки
К>// поскольку ссылка на функцию помещена в VMT этого класса
MT>>class Shape2 { virtual void draw() = 0; }
К>// Эту функцию можно не определять (хотя можно и определить).
К>// А вот VMT с нуллевой ссылкой уже быть не может,
Может, еще как может. Причем возможен даже вызов чисто виртуальной функции.
К>// поэтому создать экземпляр класса Shape2 невозможно
MT>>
Но есть противоречивые ответы...
Поэтому уточните пожалуста — должен ли я определять чисто виртуальную функциу в производном классе, или можно не определять?
MT>Д. день!
MT>Чем отличается виртуальная функция от чистой виртуальной функции? MT>На примере двух классов:
MT>
Здравствуйте, Аноним, Вы писали:
MT>>>class Shape2 { virtual void draw() = 0; } К>>// Эту функцию можно не определять (хотя можно и определить). К>>// А вот VMT с нуллевой ссылкой уже быть не может,
А>Может, еще как может. Причем возможен даже вызов чисто виртуальной функции.
Это что за компилер такой?
VC6 — не создает!
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Это очень легко сделать. Деструктор абстрактной базы установит вптр на таблицу абстрактной базы,которая содержит некоторую заглушку. Вызови в деструкторе абстрактной базы функцию, которая вызывает чисто виртуальную функцию и ага.
Of course, the code must be complete enough to compile and link.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>Это очень легко сделать. Деструктор абстрактной базы установит вптр на таблицу абстрактной базы,которая содержит некоторую заглушку. Вызови в деструкторе абстрактной базы функцию, которая вызывает чисто виртуальную функцию и ага.
Не, ну понятно, что обойти можно все, что угодно!
Мы-то говорим о стандартных средствах языка!
И вопрос так ставился изначально. А потом чел пишет вдруг, что у него создает.
Так пусть приведет, как стандарт обходит.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[4]: Virtual and Pure Virtual function
От:
Аноним
Дата:
25.08.03 13:56
Оценка:
Здравствуйте, LaptevVV, Вы писали:
А>>Может, еще как может. Причем возможен даже вызов чисто виртуальной функции. LVV>Это что за компилер такой? LVV>VC6 — не создает!
Создает.
class b;
void g(b*);
class b
{
public:
b()
{
g(this);
}
virtual void f() = 0;
};
class d : public b
{
public:
void f()
{}
};
void g(b* bb)
{
bb->f();
}
int main()
{
d dd; // Наслаждаемся эффектом!return 0;
}
Кодт говорит, что не может быть VMT с нулевой ссылкой, Аноним говорит, что может — т.е. для абстрактного класса создается VMT. Я согласен с Анонимом, и пример, который я привел, это показывает (по-моему)
Of course, the code must be complete enough to compile and link.
Re[4]: Virtual and Pure Virtual function
От:
Аноним
Дата:
25.08.03 14:05
Оценка:
Здравствуйте, LaptevVV, Вы писали:
LVV>VC6 — не создает!
Кстати, именно VC6 грешит тем, что позволяет создавать временные объекты абстрактных типов.
Здравствуйте, Аноним, Вы писали:
А>Создает. Пардон-с!!! Где ж тут создание есть создание объекта абстракного класса?
Смотри в коде комментарии А>
А>class b;
А>void g(b*);
А>class b
А>{
А>public:
А> b(){g(this);}
А> virtual void f() = 0; //чисто виртуальная
А>};
А>class d : public b //наследник
А>{
А>public:
А> void f(){} //а вот и реализация!!!!!
А>};
А>void g(b* bb)
А>{
bb->>f();
А>}
А>int main()
А>{
А> d dd; // Пардон!! Создали не из абстрактного класса
А> return 0;
А>}
А>
Ну и что, что тело пустое у функции в наследнике — это все равно реализация! Так что создал ты нормальный объект.
А в функции g у тебя не объект, а указатель на объект. А это можно.
А ты вызвал бы g и посмотрел, что получается.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Вы не о том. А о чем Аноним и лоренцо — смотри выше в моем примере. Кроме того, вижуал действительно позволяет создавать объект абстрактного класса (если я ничего не путаю) — тут как-то об этом говорили, может Аноним подробнее скажет
Of course, the code must be complete enough to compile and link.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>Кодт говорит, что не может быть VMT с нулевой ссылкой, Аноним говорит, что может — т.е. для абстрактного класса создается VMT. Я согласен с Анонимом, и пример, который я привел, это показывает (по-моему)
Если б я реализовывал, то конечно создавал бы. Наследовать потом проще. Разве что указатели оставлять нулевые, подчеркивая абстрактность. Наверное, они так же рассуждали.
Но, уважаемый Lorenzo, поясните мне неучу, почему аноним считает (и приводит пример), что абстрактный объект создается.
Я откомеентарил — у него ж там все от наследника. Указатель в функции g — так указатель вроде не запрещается создавать даже на
class aaa;
aaa *p;
а уж у него вообще класс определен.
Что я непонимаю?
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[8]: Virtual and Pure Virtual function
От:
Аноним
Дата:
25.08.03 14:30
Оценка:
Здравствуйте, LaptevVV, Вы писали:
LVV>Но, уважаемый Lorenzo, поясните мне неучу, почему аноним считает (и приводит пример), что абстрактный объект создается.
Я так не считаю и примера такого не привожу.
Re[6]: Virtual and Pure Virtual function
От:
Аноним
Дата:
25.08.03 14:31
Оценка:
Здравствуйте, LaptevVV, Вы писали:
LVV>Пардон-с!!! Где ж тут создание есть создание объекта абстракного класса?
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, LaptevVV, Вы писали:
LVV>>Но, уважаемый Lorenzo, поясните мне неучу, почему аноним считает (и приводит пример), что абстрактный объект создается.
А>Я так не считаю и примера такого не привожу.
А вы ТОТ аноним?
Значит, пример доказывал создание VMT с нулевой ссылкой, да?
Если так, то и пусть себе. Это, ИМХО, нормально. Я так бы тож делал.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Incidentally, it is possible to provide a definition for a pure virtual function. That is, you could provide an implementation for Shape::draw, and C++ wouldn't complain, but the only way to call it would be to fully specify the call with the class name: ¤ Item E36, P11
Shape *ps = new Shape; // error! Shape is abstract
Shape *ps1 = new Rectangle; // fine
ps1->draw(); // calls Rectangle::draw
Shape *ps2 = new Ellipse; // fine
ps2->draw(); // calls Ellipse::draw
ps1->Shape::draw(); // calls Shape::draw
ps2->Shape::draw(); // calls Shape::draw
LVV>Здравствуйте, Аноним, Вы писали:
А>>Здравствуйте, LaptevVV, Вы писали:
LVV>>>Но, уважаемый Lorenzo, поясните мне неучу, почему аноним считает (и приводит пример), что абстрактный объект создается.
А>>Я так не считаю и примера такого не привожу. LVV>А вы ТОТ аноним? LVV>Значит, пример доказывал создание VMT с нулевой ссылкой, да? LVV>Если так, то и пусть себе. Это, ИМХО, нормально. Я так бы тож делал.
Здравствуйте, MT, Вы писали:
MT>Incidentally, it is possible to provide a definition for a pure virtual function. That is, you could provide an implementation for Shape::draw, and C++ wouldn't complain, but the only way to call it would be to fully specify the call with the class name: ¤ Item E36, P11 MT>
MT>Shape *ps = new Shape; // error! Shape is abstract
MT>Shape *ps1 = new Rectangle; // fine
ps1->>draw(); // calls Rectangle::draw
MT>Shape *ps2 = new Ellipse; // fine
ps2->>draw(); // calls Ellipse::draw
ps1->>Shape::draw(); // calls Shape::draw
ps2->>Shape::draw(); // calls Shape::draw
MT>
Кажется я эту книжку читал!
Но это я и сам знаю, я проверил же пример анонима. Просто я не обратил внимание на фразу Кодта, о том, что vmt не создается из-за нулевых ссылок. А сыр-бор шел как раз вокруг этого. То есть там под ковром абстрактный объект неявно существует.
А абстрактный объект в явном виде по стандарту создать нельзя. И мои компиляторы в этом месте соответствуют.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Другой Аноним, Вы писали:
ДА>Здравствуйте, LaptevVV, Вы писали:
LVV>>А абстрактный объект в явном виде по стандарту создать нельзя. И мои компиляторы в этом месте соответствуют.
ДА> А вы и компиляторы выпускаете?
Могем! Ось, помнится, написали, могем и компилер слабать. Токмо пока не про С++, а просто С. В С++ плюсов много, одному не поднять.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Кстати, по поводу создания объектов абстрактных классов. Посмотрите такое (у меня сейчас нету под рукой VC6.0 — кто-то как-то на такое вроде жаловался):