Что вы думаете об этом куске кода C ++:
Polygon* p;
if(shape=="Rectangle")
p = new Rectangle();
else if(shape=="Triangle")
p = new Triangle();
else
exit(EXIT_FAILURE);
где Прямоугольник и Треугольник происходят от Полигона базового класса.
Идея заключается в том, что мне нужно использовать конкретные методы из производных классов, не зная, какой класс мне нужен, пока программа не запустится.
Есть ли лучший способ сделать это? Он компилируется, но мне интересно, вызван ли деструктор выбранного производного класса, чтобы определенные переменные были правильно освобождены.
Вспомогательный вопрос: включает ли операция dynamic_cast копию данных?
Спасибо 🙂
РЕДАКТИРОВАТЬ:
Спасибо за все эти очень поучительные ответы.
Теперь давайте скажем метод
bool isIsosceles()
реализован в треугольнике, но не в прямоугольнике.
Тогда звоню прямо сейчас
p->isIsosceles()
очевидно потерпит неудачу.
Мои первые идеи были бы либо:
Объявите и реализуйте isIsosceles () как виртуальный метод в базовом классе Polygon как
virtual bool isIsosceles()
{
cout << "Isosceles means nothing to me." << endl;
exit(EXIT_FAILURE);
}
или использование dynamic_cast в операторе if.
Является ли какой-либо из этих вариантов хорошей практикой здесь?
Большое спасибо
Неявный даункинг с использованием нового ОК?
Здесь не происходит «уныние»: это прямое использование полиморфного поведения. Ваш Polygon *
указатель на базовый класс; Ваш конструкционный код создает объект, который абстрагирует реализацию посредством использования виртуальных функций-членов.
Он компилируется, но мне интересно, вызван ли деструктор выбранного производного класса, чтобы определенные переменные были правильно освобождены.
При условии, что деструктор в базовом классе является виртуальным (что и должно быть), освобождая объект через указатель базового класса, все сделает правильно:
delete p;
Есть ли лучший способ сделать это?
Вы могли бы использовать std::unique_ptr<Polygon>
автоматизировать процесс удаления вашего Polygon
объект. Использование умного указателя разрушит объект, когда указатель выйдет из области видимости.
Делает
dynamic_cast
операция связана с копией данных?
Я предполагаю, что вы не пользуетесь dynamic_cast
здесь, потому что Polygon
объявляет виртуальные функции-члены для всех операций, представляющих интерес. Тем не менее, когда вы делаете dynamic_cast
, копирование данных не происходит. Система проверяет, разрешено ли приведение, и либо дает вам правильно приведенный указатель, либо возвращает nullptr
,
Будет работать, если вы помните delete p
и деструктор Polygon
является virtual
, Это жизненно важно.
Лучшая альтернатива — завернуть его в умный указатель.
Это не уныло. Вы фактически используете здесь полиморфизм, то есть создаете объект некоторого производного типа, который вы будете использовать как объект их базового типа.
Вы можете сделать это, но, как и все, что вы выделяете с новым, используйте delete. Следует также отметить, что вам нужен виртуальный деструктор в Polygon
, как это:
class Polygon {
virtual ~Polygon();
}
в противном случае вы получите нарезку объектов, то есть объекты будут «наполовину удалены».
Дополнительное примечание: к вашему сведению, уныние будет, используя ваши классы, делать следующее:
Polygon* polygon = new Triangle();
Triangle* triangle = dynamic_cast<Triangle*>(polygon);
// Check that we effectively had a triangle under this polygon pointer
if(triangle){
//do something with the triangle
}
Идея заключается в том, что мне нужно использовать конкретные методы из производных классов, не зная, какой класс мне нужен, пока программа не запустится.
Этот тип побеждает цель полиморфизма, которая позволяет вам выполнять операции, не зная, с каким производным типом вы работаете.
Есть ли лучший способ сделать это?
Это зависит от того, чего вы на самом деле пытаетесь достичь. Например, то, что вы показали, может быть реализовано как часть фабрики классов. Но вы не показали, как вы используете эти объекты после их создания, поэтому трудно сказать, правильно ли вы поступаете или нет.
Интересно, называется ли деструктор выбранного производного класса, чтобы определенные переменные были должным образом освобождены.
Это будет только если ~Polygon()
объявлен как virtual
,
включает ли операция dynamic_cast копирование данных?
№ А dynamic_cast
просто выполняет поиск во время выполнения, чтобы получить указатель на другой раздел VMT для того же объекта.