Что такое и с чем едят виртуальные методы понятно, но совершенно не понятно назначение виртуальных конструкторов с деструкторами. Так же не понятна технология их использования, ведь не может же производный класс иметь имя идентичное имени предка...
Я в полном недоумении, помогите пожалуйста, есжели кто в состоянии...
Здравствуйте Lummox, Вы писали:
L>Что такое и с чем едят виртуальные методы понятно, но совершенно не понятно назначение виртуальных конструкторов с деструкторами. Так же не понятна технология их использования, ведь не может же производный класс иметь имя идентичное имени предка...
С виртуальными деструкторами проще — они нужны, чтобы объект, адресуесый указателем на базовый класс, корректно уничтожался. Например:
class A
{
public:
/* virtual */ ~A() {};
};
class B : public A
{
private:
char *buf;
public:
B() { buf = new char[255]; }
~B() { delete [] buf; }
};
int main(int argc, char* argv[])
{
A *ptr = new B;
delete ptr;
return 0;
}
Если не объявить деструктор виртуальным, то в строке delete ptr; вызовется только деструктор класса A (которому соответствует тип указателя ptr), и память, выделенная под B::buf, останется неосвобождённой.
Вопрос про виртуальные конструкторы более интересен. Дело в том, что в C++ таких конструкторов не существует. "Виртуальный конструктор" — это скорее паттерн ООП, который легко реализовать на C++. Его ещё называют фабричным методом. Виртуальный конструктор — это виртуальный метод, который определяет интерфейс для создания некоторого объекта, но оставляет её реализацию классам-потомкам. Типичное применение этого паттерна — клонирование объектов, тип которых неизвестен на этапе компиляции.
class A
{
public:
virtual A *Clone() { return new A; }
};
class B : public A
{
public:
A *Clone() { return new B; }
};
extern A *ptr; /* мы не знаем, на какой объект ссылаемся */
...
A *copy = ptr->Clone(); /* создаём копию объекта, не зная его точного типа */
В этом примере Clone можно назвать виртуальным конструктором. Использовать его гораздо удобнее, чем определять тип объекта, адресуемого ptr, через RTTI, а затем создавать нужную копию в switch'е. Кроме того, такое решение оказывается более гибким и лучше соответствует идеалам ООП.
--
Я думал, ты огромный страшный Бажище,
А ты недоучка, крохотный Бажик...
Здравствуйте Lummox, Вы писали:
L>Что такое и с чем едят виртуальные методы понятно, но совершенно не понятно назначение виртуальных конструкторов с деструкторами. Так же не понятна технология их использования, ведь не может же производный класс иметь имя идентичное имени предка...
Ух ты :))) А где это есть виртуальные конструкторы? Они и так в некотором роде виртуальные :) В конструкторе происходит заполнение виртуальной таблицы. Кроме того, при вызове конструктора потомка всегда перед ним вызовется конструктор предка.
Ну а в деструкторе вот какой смысл. Если он не виртуальный, то при вызове деструктора потомка деструктор предка НЕ будет вызван. Иначе — будет вызван после потомка.
Антон.
Re[2]: Век живи, век учись. За конструкторы - спасибо...
Здравствуйте Lummox, Вы писали:
L>Что такое и с чем едят виртуальные методы понятно, но совершенно не понятно назначение виртуальных конструкторов с деструкторами. Так же не понятна технология их использования, ведь не может же производный класс иметь имя идентичное имени предка... L>Я в полном недоумении, помогите пожалуйста, есжели кто в состоянии... :???:
Смысла в виртуальном конструкторе нет, как мне кажется, а вот виртуальные деструкторы — полезная штука при наследовании классов. Вируальным деструктор объявляется только в базовом классе, во всех наследуемых классах деструктор будет виртуальным по умолчанию. Виртуальный д. гарантирует, что все необходимые деструкторы для объекта такого класса будут вызваны, каким бы образом ты не вызывал для него delete. Особенно это показательно, когда создаешь массив типа базового класса, который фактически содержит указатели на объекты разных производних классов. По завершению работы нужно очистить память — вот для каждого такого указателя вызываешь delete, хотя указатель и типа базового класса, для соотв. обекта вызовуться деструкторы в обратном порядке тому, в котором вызывались конструкторы, для всех классов иерархии...
Здравствуйте Alexander Shargin, Вы писали:
AS>Вопрос про виртуальные конструкторы более интересен. Дело в том, что в C++ таких конструкторов не существует. "Виртуальный конструктор" — это скорее паттерн ООП, который легко реализовать на C++. Его ещё называют фабричным методом. Виртуальный конструктор — это виртуальный метод, который определяет интерфейс для создания некоторого объекта, но оставляет её реализацию классам-потомкам. Типичное применение этого паттерна — клонирование объектов, тип которых неизвестен на этапе компиляции.
AS>
AS>class A
AS>{
AS>public:
AS> virtual A *Clone() { return new A; }
AS>};
AS>class B : public A
AS>{
AS>public:
AS> A *Clone() { return new B; }
AS>};
AS>extern A *ptr; /* мы не знаем, на какой объект ссылаемся */
AS>...
AS>A *copy = ptr->Clone(); /* создаём копию объекта, не зная его точного типа */
AS>
AS>В этом примере Clone можно назвать виртуальным конструктором. Использовать его гораздо удобнее, чем определять тип объекта, адресуемого ptr, через RTTI, а затем создавать нужную копию в switch'е. Кроме того, такое решение оказывается более гибким и лучше соответствует идеалам ООП.
Хотелось бы уточнить, что клонирование и фабрика и всеж таки две разные вещи. Приведенный пример, это клонирование. А абстрактная фабрика, это отдельный класс, который умеет создавать экземпляры объектов, и наличие этой абстрактной фабрики позволяет инкапсулировать способ создания конкретных экземпляров. Простейший пример:
/* Определение IA, IB, A и B */class IObjFactory {
public:
virtual IA* newA() = 0;
virtual IB* newB() = 0;
};
class ObjFactory : public IObjFactory {
public:
virtual IA* newA() { return new A(); }
virtual IB* newB() { return new B(12); }
};
Здравствуйте ZORK, Вы писали:
AS>>В этом примере Clone можно назвать виртуальным конструктором. Использовать его гораздо удобнее, чем определять тип объекта, адресуемого ptr, через RTTI, а затем создавать нужную копию в switch'е. Кроме того, такое решение оказывается более гибким и лучше соответствует идеалам ООП.
ZORK>Хотелось бы уточнить, что клонирование и фабрика и всеж таки две разные вещи. Приведенный пример, это клонирование. А абстрактная фабрика, это отдельный класс, который умеет создавать экземпляры объектов, и наличие этой абстрактной фабрики позволяет инкапсулировать способ создания конкретных экземпляров. Простейший пример:
Я говорил не о фабрике, а о фабричном методе. Это два совершенно разных паттерна, хотя они и применяются для схожих целей. Кстати, применение фабричного метода (то бишь виртуального конструктора) не ограничивается клонированием. Например, в класс окна можно ввести виртуальные методы CreateMenu, CreateBorder, CreateCaption и пр., которые пользователь может переопределять в производных классах для придания окну нестандартного вида. И они также будут являться фабричными методами.
--
Я думал, ты огромный страшный Бажище,
А ты недоучка, крохотный Бажик...
Здравствуйте Alexander Shargin, Вы писали:
AS>Здравствуйте ZORK, Вы писали:
AS>>>В этом примере Clone можно назвать виртуальным конструктором. Использовать его гораздо удобнее, чем определять тип объекта, адресуемого ptr, через RTTI, а затем создавать нужную копию в switch'е. Кроме того, такое решение оказывается более гибким и лучше соответствует идеалам ООП.
ZORK>>Хотелось бы уточнить, что клонирование и фабрика и всеж таки две разные вещи. Приведенный пример, это клонирование. А абстрактная фабрика, это отдельный класс, который умеет создавать экземпляры объектов, и наличие этой абстрактной фабрики позволяет инкапсулировать способ создания конкретных экземпляров. Простейший пример:
AS>Я говорил не о фабрике, а о фабричном методе. Это два совершенно разных паттерна, хотя они и применяются для схожих целей. Кстати, применение фабричного метода (то бишь виртуального конструктора) не ограничивается клонированием. Например, в класс окна можно ввести виртуальные методы CreateMenu, CreateBorder, CreateCaption и пр., которые пользователь может переопределять в производных классах для придания окну нестандартного вида. И они также будут являться фабричными методами.
Понятно, то есть речь о Factory Method (http://rampages.onramp.net/~huston/dp/factoryMethod.html) — Виноват!-) Всеж таки, как мне кажется, клонирование это не самый удачный пример, так как он больше демонстрирует Prototype Pattern, а вот CreateWhatever() — это действительно хорошая демонстрация Factory Methods
Здравствуйте ZORK, Вы писали:
AS>>Я говорил не о фабрике, а о фабричном методе. Это два совершенно разных паттерна, хотя они и применяются для схожих целей. Кстати, применение фабричного метода (то бишь виртуального конструктора) не ограничивается клонированием. Например, в класс окна можно ввести виртуальные методы CreateMenu, CreateBorder, CreateCaption и пр., которые пользователь может переопределять в производных классах для придания окну нестандартного вида. И они также будут являться фабричными методами.
ZORK>Понятно, то есть речь о Factory Method (http://rampages.onramp.net/~huston/dp/factoryMethod.html) — Виноват!-) Всеж таки, как мне кажется, клонирование это не самый удачный пример, так как он больше демонстрирует Prototype Pattern, а вот CreateWhatever() — это действительно хорошая демонстрация Factory Methods
Действительно, метод Clone имеет большое значение для паттерна "Прототип", но его применение гораздо шире. В том примере, который я приводил, не ничего похожего на набор прототипов или реестр прототипов для конструирования объектов. Есть только метод Clone. И он вполне подходит под определение виртуального конструктора, так как: а) виртуален и б) создаёт объекты.
А насчёт неудачности примера могу согласиться — он получился на стыке паттернов, что порожджает некоторую путаницу. Собственно, меня сбил с истинного пути Страуструп, который, насколько я помню, тоже демонстрировал метод Clone в разделе, посвящённом виртуальным конструкторам. Точнее не скажу, так как отдал Страуструпа на прочтение.
--
Я думал, ты огромный страшный Бажище,
А ты недоучка, крохотный Бажик...