|
||||
|
Шаг 25 - Как сделать виртуальной свободную функцию. Чаще всего этот прием я видел в отношении оператора operator‹‹. Точнее, не чаще, а всегда. На нем и разберем. Пусть у нас есть иерархия классов, и мы хотим определить диагностическую функцию Dump(). Она должна вываливать диагностику в заданное что-то (CDestination). У нас есть два варианта: или сделать функцию виртуальной в иерархии классов: class CBase { virtual void Dump(CDestination& ds) = 0; }; class CFirst: public CBase { void Dump (CDestination& ds); }; class CSecond: public CBase { void Dump (CDestination& ds); }; Или перегружать ее для каждого класса иерархии или в классе, или в свободной функции: CDestination { void Dump (CFirst& fs); void Dump (CSecond& sc); }; void Dump (CDestination& ds, CThird& td); void Dump (CDestination& ds, CFourth& fr); Ясно, первый вариант предпочтительнее. Во-первых, он обеспечивает полиморфное поведение. Во-вторых, своей диагностикой класс занимается сам, что тоже большой плюс. А второй способ почти невозможен: переписывать класс вывода каждый раз при появлении нового потомка в иерархии нереально (в двойной диспетчеризации дело другое, там просто нет иного выхода); в конце концов, он может быть в купленной библиотеке. Но у второго варианта есть одно преимущество: функцию Dump() можно обозвать оператором operator‹‹, и это будет выглядеть весьма презентабельно: // Это декларация CDestination { CDestination& operator‹‹ (CFirst& fs); }; CDestination& operator‹‹ (CDestination& ds, CSecond& sc); // А это применение dStream ‹‹ dObject; Как сделать так, чтобы сохранить замечательное полиморфное поведение первого варианта, и применить эту радость идиота operator‹‹? Легко: пусть operator‹‹ вместо реальной работы просто вызывает виртуальную Dump(). Именно так сделано в MFC - объект afxDump вызывает виртуальную Dump() именно через operator‹‹. (Можно что угодно говорить про Microsoft, но факт есть факт - огромное число полезных и интересных приемов использовано в их продуктах и "… взять их у нее - наша задача!"). #include ‹iostream.h› class CNoChange; class CBase { public: virtual void passTo (CNoChange& _cb) { cout ‹‹ "base passed" ‹‹ endl; } }; class CFirst: public CBase { public: void passTo (CNoChange& _cb) { cout ‹‹ "first passed" ‹‹ endl; } }; class CSecond: public CBase { public: void passTo (CNoChange& _cb) { cout ‹‹ "second passed" ‹‹ endl; } }; class CNoChange { public: int a; // Это вариант с оператором - членом класса. CNoChange& operator‹‹ (CBase& _cb) { _cb.passTo(*this); return *this; } }; // а это - свободная функция. //CNoChange& operator‹‹ (CNoChange& _nc, CBase& _cb) // {_cb.passTo(_nc); return _nc;}; // проверить надо. int main() { CNoChange nc; CFirst fs; CSecond sc; nc‹‹fs; nc‹‹sc; return 0; } |
|
||
Главная | Контакты | Нашёл ошибку | Прислать материал | Добавить в избранное |
||||
|