Йа волосат и бородат!
...когда я бежал к глазодерам. =О.о=

Все знают ситуацию, когда нужно пронаследовать несколько детишек от некоторого класса. И все знают, чем плохо перегружать в детишке невиртуальный метод, а именно что будет, если попробовать вызвать перегруженный метод по указателю на родителя. (перегруженный метод банально не вызовется, ибо в таблицу виртуалов не попадет)
Так вот для преодоления такой фигни в случае закрытого кода с родительским классом возникла мысль написать что-нить вроде:
template <typename Derived_class>
class Middle_base : public Base {
public:
Derived_class * const operator-> () {
return reinterpret_cast <Derived_class * const> (this);
}
};

Наследоваться надо вот так:
class Child : public Middle_base <Child>
{
// ...
};

При этом получается, что в момент наследования от Middle_base класс Child уже обьявлен в той же строке. :) Единственный минус конструкции - что обращаться надо по указателю на Middle_base.

Единственный вопрос возникает - нафига при таком подходе вообще нужны виртуальные методы? =О.о=

ЗЫ: Учитывая, что это была только мысля, которую я еще не довёл до ума...

UPD: К сожалению, на проверке метода выявились 2 проблемы:
1) не происходит вызова Middle_base::operator-> (). Вызов сразу уходит в Base;
2) совершенно непонятно, что делать с самим классом Middle_base . Ибо каждый из них порождает отдельный тип, а это как бы мешает в случае кучи детишек. :/

@темы: странные мысли в моей голове..., программистское

Комментарии
25.08.2009 в 15:06

прикольно.
Ну на первый взгляд все намана, кроме одного:
Derived_class * const operator-> () {
return reinterpret_cast (this);
}

вернет самого себя, а оператор -> задан у него так чтоб вернуть себя - рекурсии не будет?

тока стоит ли виртуализовавать невиртуальные методы? Понятно, это зависит от ситуации....
В принципе с тем же успехом можно в middleclass объявить нужную виртуальную функуию и сначала кастовать в middleclass. Тебе и тут нуна делаеть такое кастование.
Еще минус: для наследников класса Child (у которого д/б своя реализация метода) будет нехорошо :(
25.08.2009 в 15:07

сорри забыл расписаться
Тимур
25.08.2009 в 15:33

Йа волосат и бородат!
Derived_class * const operator-> () вернет самого себя, а оператор -> задан у него так чтоб вернуть себя - рекурсии не будет?
нет, он возвращает не самого себя, а своего наследника.

В принципе с тем же успехом можно в middleclass объявить нужную виртуальную функуию и сначала кастовать в middleclass. Тебе и тут нуна делаеть такое кастование.
А если нужна именно перегрузка?

Еще минус: для наследников класса Child (у которого д/б своя реализация метода) будет нехорошо
Ага... есть такое.
28.08.2009 в 09:00

Derived_class * const operator-> () вернет самого себя, а оператор -> задан у него так чтоб вернуть себя - рекурсии не будет?
нет, он возвращает не самого себя, а своего наследника.

да, нормально все, возвращается ж указатель, а не сцылка.

А если нужна именно перегрузка?
В смысле?! как это соотносится с первонамальным вопросом?

Кстати, варварский (грю сразу, чтоб не холиварили) способ в принципе пройдет?
Тут есть вопрос. в хранится ли либе таблица виртуальных функций для класса, реализованного в этой либе, или эта таблица строится при компиляции проекта, который ее в себя включает?
Если второе, то в h-файле можно в наглую сказать ему виртуал %(((
28.08.2009 в 09:05

Йа волосат и бородат!
да, нормально все, возвращается ж указатель, а не сцылка.
Ссылка тоже прокатила бы, кстати. Они тоже прекрасно преобразуются, если ты не знал. :)

Учитывая UPD и провал тестов, есть ли смысл продолжать дискуссию?
28.08.2009 в 11:06

а разве operator -> может возвращать не указатель?
В борладне точно низя, интересно - есть которые позволяют?

хз. у меня других идей нету.
чтобы ИЗНУТРИ класса закрытой библиотеки вызывался унаследованный метод (от невиртуального) - ты это в принципе не сделаешь, т.к. код уже скомпилирован....
а если извне - то эта проблема решаема...
28.08.2009 в 19:38

Йа волосат и бородат!
а разве operator -> может возвращать не указатель?
нет, он возвращает только указатель. Однако, сделать метод вида Type & Method () тоже можно.

Расширенная форма

Редактировать

Подписаться на новые комментарии