Здравствуйте Sashko, Вы писали:
S>Может не поверишь, Игорь, но иногда небольшой смысл есть ;). С virtual наследованием (хотя эта вещь закладывалась как раз для полиморфного наследования) можно делать вот такую вещь
S>При виртуальном наследовании, в конструкторе наследника (любого уровня) мы должны указывать как инициализируется базовый виртуальный класс. Если в списке инициализации конструктора наследника, явно не указан конструктор базового виртуального класса, то будет использоваться конструктор по умолчанию (если такового нет, то компилятор выдаст ошибку). Таким образом, в наследнике любого уровня, легко можно проинициализировать базовый класс (в TurboVision было похожее использование виртуального наследования). Не спорю, что, то же самое можно сделать и без виртуального наследования, удобно это или нет, решать самому.
На этом принципе основан также родственный трюк, позволяющий обозначать определенные классы как финальные, т.е. как классы, от которых нельзя наследовать:
class VB
{
friend class CFinal;
private:
VB() {}
};
// Пример финального классаclass CFinal : private virtual VB
{
};
В данном примере от класса 'CFinal' нельзя унаследовать никакие другие классы. Если попытаться это сделать, то на класс-наследник будет возложена обязанность констуирования виртуальной базы 'VB'. А он этого сделать не может, т.к. не имеет доступа к конструктору класса 'VB'.
Этот прием можно оформить более универсально через шаблоны:
template <class T_>
class CInheritanceStopper
{
friend class T_;
private:
CInheritanceStopper() {}
};
////////////////////////////////////
// Пример финального классаclass CFinal : private virtual CInheritanceStopper<CFinal>
{
};
Или еще более элегантный вариант:
template <class T_> class CInheritanceStopper;
template <class T_>
class CInheritanceStopper_
{
friend class T_;
friend class CInheritanceStopper<T_>;
private:
CInheritanceStopper_() {}
};
template <class T_>
class CInheritanceStopper : private virtual CInheritanceStopper_<T_> {};
////////////////////////////////////
// Пример финального классаclass CFinal : CInheritanceStopper<CFinal>
{
};
Best regards,
Андрей Тарасевич
Re[6]: virtual base class для чего обычно юзается?
АТ>Строго говоря, "метод не имеет реализации" и "является чистим виртуальным" — это разные вещи. Никто не запрещает чисто виртуальному методу иметь реализацию:
АТ>
А это чего-то новенькое! По поводу того, что "никто не запрещает", хочу обратить Ваше внимание на стандарт c++ от 1998 г. п.10.4, там по-моему ясно все написано. Кстати на моем компайлере (C++ Builder 5.0) это, естественно, не компилится.
Re[7]: virtual base class для чего обычно юзается?
АТ>>Строго говоря, "метод не имеет реализации" и "является чистим виртуальным" — это разные вещи. Никто не запрещает чисто виртуальному методу иметь реализацию:
class a {
public:
virtual void f() = 0
{ ... }
};
grs>А это чего-то новенькое! По поводу того, что "никто не запрещает", хочу обратить Ваше внимание на стандарт c++ от 1998 г. п.10.4, там по-моему ясно все написано. Кстати на моем компайлере (C++ Builder 5.0) это, естественно, не компилится.
Отсылая к тому же источнику, добавлю, что нельзя, действительно, привести в объявлении одновременно =0 и реализацию, однако можно привести определение метода отдельно от объявления.
class a {
public:
virtual void f() = 0;
};
void a::f() {};
Именно так пишут чисто виртуальные деструкторы...
С уважением,
Сергей
Re[7]: virtual base class для чего обычно юзается?
grs>А это чего-то новенькое! По поводу того, что "никто не запрещает", хочу обратить Ваше внимание на стандарт c++ от 1998 г. п.10.4, там по-моему ясно все написано.
Вот, кстати, и цитата аккурат оттуда : "A pure virtual function need be defined only if explicitly called with the qualified-id syntax (5.1)"
То есть "чисто виртуальная функция обязательно должна быть определена только в случае если явно вызывается..." То есть если вызывается метод с явной квалификацией класса, например, a::f(), то будь он хоть pure, реализация должна быть. В других случаях реализация не нужна
С уважением,
Сергей
Re[8]: virtual base class для чего обычно юзается?
Здравствуйте Brother, Вы писали:
B>Вот, кстати, и цитата аккурат оттуда : "A pure virtual function need be defined only if explicitly called with the qualified-id syntax (5.1)" B>То есть "чисто виртуальная функция обязательно должна быть определена только в случае если явно вызывается..." То есть если вызывается метод с явной квалификацией класса, например, a::f(), то будь он хоть pure, реализация должна быть. В других случаях реализация не нужна :)
Спасибо за уточнение! Просто приведенный в примере код малость резанул по глазам и я не совсем обратил внимание на текст над ним и напрасно... А так, никто не спорит: там ниже даже разрешается переопредлять обычную функцию чисто виртуальной, хотя на мой взгляд — это уже извращение.
Re[7]: virtual base class для чего обычно юзается?
Здравствуйте grs, Вы писали:
АТ>>Строго говоря, "метод не имеет реализации" и "является чистим виртуальным" — это разные вещи. Никто не запрещает чисто виртуальному методу иметь реализацию:
АТ>>
grs>А это чего-то новенькое! По поводу того, что "никто не запрещает", хочу обратить Ваше внимание на стандарт c++ от 1998 г. п.10.4, там по-моему ясно все написано. Кстати на моем компайлере (C++ Builder 5.0) это, естественно, не компилится.
ОК, я ошибся, поместив определение чистого виртуального метода в определение класса. Этого действительно делать нельзя, согласно Стандарту (почему — непонятно). Тем не менее определение у такого метода может быть, как тут уже сказали, только обязательно за пределами класса.
Best regards,
Андрей Тарасевич
Re[10]: virtual base class для чего обычно юзается?
Здравствуйте Sashko, Вы писали:
S>Здравствуйте Юнусов Булат, Вы писали:
ЮБ>>Вроде теперь ясно, это чтобы хитро управлять инициализацией какого нибудь класса вплоть до самых далеких предков, если какая нибудь (нестандартная) надобность возникнет.
S>Нет, это только в мнономорфном (мне больше нравится слово одиночном) наследование так. Вообще то виртуальное наследование (думаю ты это знаешь) введено для того что бы при множественном наследовании, можно было сделать так, что в структуре объекта наследника был только один экземпляр какого-то базового класса (да же если каждая из подветвей иерархии наследует этот базовый класс). А хитрое управление инициализацией, это как следствие.
Коллеги, для полноты охвата темы "виртуальное наследование", надо упомянуть,
что это виртуальное наследование хотя и дешевое, но совсем не бесплатное удовольствие.
Плата такова:
1. при вызове виртуальных функций виртуального базового класса,
появляется лишняя косвенность.
Соответсвенно вызов происходит чуть медленнее.
2. Размер класса имеющего виртуального родителя увеличивается на размер поля
в котором хранится смещение виртуального родителя в составе потомка. (4 байта)
Именно при помощи этого поля происходит обращение к данным виртуального родителя
и к его виртуальным функциям.
Потому думаю не стоит применять этот механизм при разработки классов-рабочих-лошадок,
для которых эффективность — главное.
А вот для монстровидных классов где главное гибкость, этот механизм вполне.
Мне так кажется...
Re[10]: virtual base class для чего обычно юзается?
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>На этом принципе основан также родственный трюк, позволяющий обозначать определенные классы как финальные, т.е. как классы, от которых нельзя наследовать: <...>
Удалено избыточное цитирование. -- ПК.
Re[9]: virtual base class для чего обычно юзается?
А я хоть убейте не могу понять, почему m_nA = 0. Видимо это связано с порядком вызова конструкторов и влиянием virtual на этот процесс. Но в чем прикол не понимаю. Help me !!!
Здравствуйте, Юнусов Булат, Вы писали:
ЮБ>Доброго времени суток.Просветите пожалуйста. ЮБ>Насколько я понимаю сабж это при множественном наследовании полезно чтоб данные не слишком пухли. А может для чего нибудь еще? Можно примерчик маленький? А то вот на бранйбенче куча вопросов с сабжем была на тесте — а я честно говоря и забыл что это такое, сдал в результате хреновенько, на три с копейками, ладно, сойдет для первого раза. Надо было вопросы куда нибудь соханять а я от волнительности чрезмерной запямятовал. Щас пытаюсь вспомнить и не получается ЮБ>Спасибо ЮБ>Булат
Не я сам до этого додумался, но знающие люди подсказали:
В Длл-ке жил класс (декл. + реализация). Длл грузилась в ран-тайм. Методы не вызывались. Причина -- в извращении имен методов компилятором(для перегрузки). Выход -- Объявляется интерфейсный класс (все методы без реализации), от него наследуется новый класс, реализующий. В Длл реализуется функция КритОбжект, конструирующая и возвращающая указатель на БАЗОВЫЙ класс, но т.к. таблица вирт. функций у него "потомочная", и разыменование происходит по ней, то все ок. Такой вот реальный пример
Re[2]: virtual base class для чего обычно юзается?
Здравствуйте, Аноним, Вы писали:
А>Не я сам до этого додумался, но знающие люди подсказали: А>В Длл-ке жил класс (декл. + реализация). Длл грузилась в ран-тайм. Методы не вызывались. Причина -- в извращении имен методов компилятором(для перегрузки). Выход -- Объявляется интерфейсный класс (все методы без реализации), от него наследуется новый класс, реализующий. В Длл реализуется функция КритОбжект, конструирующая и возвращающая указатель на БАЗОВЫЙ класс, но т.к. таблица вирт. функций у него "потомочная", и разыменование происходит по ней, то все ок. Такой вот реальный пример
Это пример использования абстрактного интерфейса, а виртуальный базовый класс здесь ни при чем.
А то вот на бранйбенче куча вопросов с сабжем была на тесте — а я честно говоря и забыл что это такое, сдал в результате хреновенько, на три с копейками, ладно, сойдет для первого раза. Надо было вопросы куда нибудь соханять а я от волнительности чрезмерной запямятовал. Щас пытаюсь вспомнить и не получается
Немного оффтоп, но все-таки:
С++ екзамен платный и заплатив за него, как я знаю, можна здавать несколько раз в течение следующих 21 дня — почему еще раз не попробовать и не записать вопросы которые там встречаются?
Или там ограничение — 3 раза в течение 21 дня?
Re[4]: virtual base class для чего обычно юзается?
Здравствуйте, Dr_Sh0ck, Вы писали:
D_S>Коллеги, прошу простить мое невежество! Просвятите! Чем отличаются "чисто виртуальные" и "абстрактные" классы (про "чисто абстрактные" слышу впервые; "чисто" — наверное жаргон ).
Есть еще "чисто конкретно" абстрактные
Неужели абстрактные — это те, у которых ВСЕ методы чисто витруальные?
Именно!
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[9]: virtual base class для чего обычно юзается?
Здравствуйте, Sashko, Вы писали:
S>Может не поверишь, Игорь, но иногда небольшой смысл есть . С virtual наследованием (хотя эта вещь закладывалась как раз для полиморфного наследования) можно делать вот такую вещь
S>
S>class CA
S>{
S>public:
S> CA() : m_nA(0) { }
S> CA(int nA) : m_nA(nA) { }
S>protected:
S> int m_nA;
S>};
S>class CB : virtual public CA
S>{
S>public:
S> CB(int nB) : CA(nB), m_nB(nB) { }
S>protected:
S> int m_nB;
S>};
S>class CC : public CB
S>{
S>public:
S> CC() : CB(1), m_nC(1) { }
S> CC(int nC) : CB(nC), CA(nC), m_nC(nC) { }
S>protected:
S> int m_nC;
S>};
S>CC с0;
S>CC с1(1);
S>
S>При виртуальном наследовании, в конструкторе наследника (любого уровня) мы должны указывать как инициализируется базовый виртуальный класс. Если в списке инициализации конструктора наследника, явно не указан конструктор базового виртуального класса, то будет использоваться конструктор по умолчанию (если такового нет, то компилятор выдаст ошибку). Таким образом, в наследнике любого уровня, легко можно проинициализировать базовый класс (в TurboVision было похожее использование виртуального наследования).
А для чего же это может пригодиться — "на пальцах" поясните, если можно. S>Не спорю, что, то же самое можно сделать и без виртуального наследования, удобно это или нет, решать самому.
В смысле — в наследнике проинициализировать базовый класс? S>В моем примере после инициализации, объекты будут иметь следующие данные S>
Ну вот еще простой пример в дополнение к сказанному:
struct A {
virtual void f() = 0;
};
struct B : /*virtual*/ A {
virtual void f() {std::cout << "f()" << std::endl;}
};
struct C : /*virtual*/ A, B {
virtual void g() {std::cout << "g()" << std::endl;}
};
int main() {
C c;
}
В таком виде пример не компилируется — в классе С существует две версии класса А, одна из которых имеет неперекрытую ЧВФ. Если раскомментировать virtual — все ок.
Да здравствует мыло душистое и веревка пушистая.
Re[2]: virtual base class для чего обычно юзается?