|
Программирование >> Перегруженные имена функций и идентификаторы
Вам ничего не напоминает? Ага, схема та же, что и при использовании static cast и dynamic cast. Так как схожесть очень убедительна, можно заключить, что такое решение проблемы более чем изящно. Виртуальные деструкторы В практически любой мало-мальски толковой книге по C++ рассказывается, зачем нужны виртуальные деструкторы и почему их надо использовать. При всем при том, как показывает практика, ошибка, связанная с отсутствием виртуальных деструкторов, повсеместно распространена. Итак, рассмотрим небольшой пример: class A public: virtual void f() = 0; ~A(); class B : public A public: virtual void f(); ~B(); Вызов компилятора gcc строкой: g++ -c -Wall test.cpp даст следующий результат: test.cpp:6: warning: class A has virtual functions but non-virtual destructor test.cpp:13: warning: class B has virtual functions but non-virtual destructor Это всего лишь предупреждения, компиляция прошла вполне успешно. Однако, почему же gcc выдает подобные предупреждения? Все дело в том, что виртуальные функции используются в C++ для обеспечения полиморфизма - т.е., клиентская функция вида: void call f(A* a) a->f(); никогда не знает о том, что конкретно сделает вызов метода f() - это зависит от того, какой в действительности объект представлен указателем a. Точно так же сохраняются указатели на объекты: std::vector<A*> a collection; a collection.push back(new B()); В результате такого кода теряется информация о том, чем конкретно является каждый из элементов a collection (имеется в виду, без использования RTTI). В данном случае это грозит тем, что при удалении объектов: for(std::vector<A*>::iterator i = ... ) delete *i; все объекты, содержащиеся в a collection, будут удалены так, как будто это - объекты класса A. В этом можно убедиться, если соответствующим образом определить деструкторы классов A и B: inline A::~A() puts( A::~A() ); inline B::~B() puts( B::~B() ); Тогда выполнение следующего кода: A* ptr = new B(); delete ptr; приведет к следующему результату: A::~A() Если же в определении класса A деструктор б1л бы сделан виртуальным (virtual ~A();), то результат б1л бы другим: B::~B() A::~A() В принципе, все сказано. Но, несмотря на это, очень многие программисты все равно не создают виртуальных деструкторов. Одно из распространенных заблуждений - виртуальный деструктор необходим только в том случае, когда на деструктор порожденных классов возлагаются какие-то нестандартные функции; если же функционально деструктор порожденного класса ничем не отличается от деструктора предка, то делать его виртуальным совершенно необязательно. Это неправда, потому что даже если деструктор никаких специальных действий не выполняет, он все равно должен быть виртуальным, иначе не будут вызваны деструкторы для объектов-членов класса, которые появились по отношению к предку. То есть: #include <stdio.h> class A public: A(const char* n); ~A(); protected: const char* name; inline A::A(const char* n) : name(n) { } inline A::~A() printf( A::~A() for %s.\n , name); class B public: virtual void f(); B(); ~B(); protected: A a1;
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |