Re[9]: virtual base class для чего обычно юзается?
От: Андрей Тарасевич Беларусь  
Дата: 21.01.02 07:50
Оценка: 178 (26) +1
Здравствуйте 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 для чего обычно юзается?
От: grs Россия  
Дата: 21.01.02 08:43
Оценка:
Здравствуйте Андрей Тарасевич, Вы писали:


АТ>Строго говоря, "метод не имеет реализации" и "является чистим виртуальным" — это разные вещи. Никто не запрещает чисто виртуальному методу иметь реализацию:


АТ>
АТ>class a {
АТ>public:
АТ>  virtual void f() = 0
АТ>    { ... }
АТ>};
АТ>


А это чего-то новенькое! По поводу того, что "никто не запрещает", хочу обратить Ваше внимание на стандарт c++ от 1998 г. п.10.4, там по-моему ясно все написано. Кстати на моем компайлере (C++ Builder 5.0) это, естественно, не компилится.
Re[7]: virtual base class для чего обычно юзается?
От: Brother Россия  
Дата: 21.01.02 13:35
Оценка:
АТ>>Строго говоря, "метод не имеет реализации" и "является чистим виртуальным" — это разные вещи. Никто не запрещает чисто виртуальному методу иметь реализацию:

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 для чего обычно юзается?
От: Brother Россия  
Дата: 21.01.02 13:56
Оценка:
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 для чего обычно юзается?
От: grs Россия  
Дата: 21.01.02 14:49
Оценка:
Здравствуйте 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 для чего обычно юзается?
От: Андрей Тарасевич Беларусь  
Дата: 21.01.02 16:37
Оценка:
Здравствуйте grs, Вы писали:

АТ>>Строго говоря, "метод не имеет реализации" и "является чистим виртуальным" — это разные вещи. Никто не запрещает чисто виртуальному методу иметь реализацию:


АТ>>
АТ>>class a {
АТ>>public:
АТ>>  virtual void f() = 0
АТ>>    { ... }
АТ>>};
АТ>>


grs>А это чего-то новенькое! По поводу того, что "никто не запрещает", хочу обратить Ваше внимание на стандарт c++ от 1998 г. п.10.4, там по-моему ясно все написано. Кстати на моем компайлере (C++ Builder 5.0) это, естественно, не компилится.


ОК, я ошибся, поместив определение чистого виртуального метода в определение класса. Этого действительно делать нельзя, согласно Стандарту (почему — непонятно). Тем не менее определение у такого метода может быть, как тут уже сказали, только обязательно за пределами класса.
Best regards,
Андрей Тарасевич
Re[10]: virtual base class для чего обычно юзается?
От: Андрей Тарасевич Беларусь  
Дата: 21.01.02 18:05
Оценка:
Здравствуйте Андрей Тарасевич, Вы писали:

АТ>Этот прием можно оформить более универсально через шаблоны:


Неприятным моментом в шаблонном варианте является то, что вообще говоря вот такой код некорректен:

template <class T_> class C { friend class T_; };


(См. Станадарт С++ 7.1.5.3/2). Сорри, если ввел кого в заблуждение.
Best regards,
Андрей Тарасевич
Re[11]: virtual base class для чего обычно юзается?
От: Рек Россия  
Дата: 23.01.02 07:18
Оценка:
Здравствуйте Sashko, Вы писали:

S>Здравствуйте Юнусов Булат, Вы писали:


ЮБ>>Вроде теперь ясно, это чтобы хитро управлять инициализацией какого нибудь класса вплоть до самых далеких предков, если какая нибудь (нестандартная) надобность возникнет.


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



Коллеги, для полноты охвата темы "виртуальное наследование", надо упомянуть,
что это виртуальное наследование хотя и дешевое, но совсем не бесплатное удовольствие.

Плата такова:

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

2. Размер класса имеющего виртуального родителя увеличивается на размер поля
в котором хранится смещение виртуального родителя в составе потомка. (4 байта)
Именно при помощи этого поля происходит обращение к данным виртуального родителя
и к его виртуальным функциям.

Потому думаю не стоит применять этот механизм при разработки классов-рабочих-лошадок,
для которых эффективность — главное.

А вот для монстровидных классов где главное гибкость, этот механизм вполне.
Мне так кажется...
Re[10]: virtual base class для чего обычно юзается?
От: Shedar  
Дата: 29.06.03 11:13
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>На этом принципе основан также родственный трюк, позволяющий обозначать определенные классы как финальные, т.е. как классы, от которых нельзя наследовать: <...>




Удалено избыточное цитирование. -- ПК.
Re[9]: virtual base class для чего обычно юзается?
От: Shedar  
Дата: 29.06.03 12:49
Оценка:
Здравствуйте, Sashko, Вы писали:

S>В моем примере после инициализации, объекты будут иметь следующие данные


S>
S>c0 = {m_nA = 0, m_nB = 1, m_nC = 1 } // а не {m_nA = 1, m_nB = 1, m_nC = 1 } как может показаться
S>c1 = {m_nA = 1, m_nB = 1, m_nC = 1 }
S>


А я хоть убейте не могу понять, почему m_nA = 0. Видимо это связано с порядком вызова конструкторов и влиянием virtual на этот процесс. Но в чем прикол не понимаю. Help me !!!

Удалено избыточное цитирование. -- ПК.
Re: virtual base class для чего обычно юзается?
От: Аноним  
Дата: 30.06.03 05:21
Оценка: 1 (1)
Здравствуйте, Юнусов Булат, Вы писали:

ЮБ>Доброго времени суток.Просветите пожалуйста.

ЮБ>Насколько я понимаю сабж это при множественном наследовании полезно чтоб данные не слишком пухли. А может для чего нибудь еще? Можно примерчик маленький? А то вот на бранйбенче куча вопросов с сабжем была на тесте — а я честно говоря и забыл что это такое, сдал в результате хреновенько, на три с копейками, ладно, сойдет для первого раза. Надо было вопросы куда нибудь соханять а я от волнительности чрезмерной запямятовал. Щас пытаюсь вспомнить и не получается
ЮБ>Спасибо
ЮБ>Булат


Не я сам до этого додумался, но знающие люди подсказали:
В Длл-ке жил класс (декл. + реализация). Длл грузилась в ран-тайм. Методы не вызывались. Причина -- в извращении имен методов компилятором(для перегрузки). Выход -- Объявляется интерфейсный класс (все методы без реализации), от него наследуется новый класс, реализующий. В Длл реализуется функция КритОбжект, конструирующая и возвращающая указатель на БАЗОВЫЙ класс, но т.к. таблица вирт. функций у него "потомочная", и разыменование происходит по ней, то все ок. Такой вот реальный пример
Re[2]: virtual base class для чего обычно юзается?
От: folk Россия  
Дата: 30.06.03 06:08
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Не я сам до этого додумался, но знающие люди подсказали:

А>В Длл-ке жил класс (декл. + реализация). Длл грузилась в ран-тайм. Методы не вызывались. Причина -- в извращении имен методов компилятором(для перегрузки). Выход -- Объявляется интерфейсный класс (все методы без реализации), от него наследуется новый класс, реализующий. В Длл реализуется функция КритОбжект, конструирующая и возвращающая указатель на БАЗОВЫЙ класс, но т.к. таблица вирт. функций у него "потомочная", и разыменование происходит по ней, то все ок. Такой вот реальный пример

Это пример использования абстрактного интерфейса, а виртуальный базовый класс здесь ни при чем.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re: virtual base class для чего обычно юзается?
От: promko Украина  
Дата: 01.07.03 08:42
Оценка:
Здравствуйте, Юнусов Булат, Вы писали:

А то вот на бранйбенче куча вопросов с сабжем была на тесте — а я честно говоря и забыл что это такое, сдал в результате хреновенько, на три с копейками, ладно, сойдет для первого раза. Надо было вопросы куда нибудь соханять а я от волнительности чрезмерной запямятовал. Щас пытаюсь вспомнить и не получается

Немного оффтоп, но все-таки:
С++ екзамен платный и заплатив за него, как я знаю, можна здавать несколько раз в течение следующих 21 дня — почему еще раз не попробовать и не записать вопросы которые там встречаются?
Или там ограничение — 3 раза в течение 21 дня?
Re[4]: virtual base class для чего обычно юзается?
От: LaptevVV Россия  
Дата: 14.09.04 05:33
Оценка: :)
Здравствуйте, Dr_Sh0ck, Вы писали:

D_S>Коллеги, прошу простить мое невежество! Просвятите! Чем отличаются "чисто виртуальные" и "абстрактные" классы (про "чисто абстрактные" слышу впервые; "чисто" — наверное жаргон ).

Есть еще "чисто конкретно" абстрактные
Неужели абстрактные — это те, у которых ВСЕ методы чисто витруальные?
Именно!
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[9]: virtual base class для чего обычно юзается?
От: LaptevVV Россия  
Дата: 14.09.04 05:42
Оценка:
Здравствуйте, 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>
S>c0 = {m_nA = 0, m_nB = 1, m_nC = 1 } // а не {m_nA = 1, m_nB = 1, m_nC = 1 } как может показаться
S>c1 = {m_nA = 1, m_nB = 1, m_nC = 1 }
S>

Хорошо бы, если б кто-нить привел бы РЕАЛЬНЫЙ пример, где это использовалось.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: virtual base class для чего обычно юзается?
От: Vamp Россия  
Дата: 14.09.04 06:09
Оценка:
Ну вот еще простой пример в дополнение к сказанному:

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 для чего обычно юзается?
От: Аноним  
Дата: 24.08.07 06:42
Оценка:
.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.