неявное понижение с использованием нового ОК?

Что вы думаете об этом фрагменте кода C++:

Polygon* p;
if(shape=="Rectangle")
    p = new Rectangle();
else if(shape=="Triangle")
    p = new Triangle();
else
    exit(EXIT_FAILURE);

где Rectangle и Triangle являются производными от Polygon базового класса.

Идея заключается в том, что мне нужно использовать определенные методы из производных классов, не зная, какой класс мне нужен, пока программа не запустится. Есть ли лучший способ сделать это? Он компилируется, но мне интересно, вызывается ли деструктор выбранного производного класса, чтобы определенные переменные были правильно освобождены.

Дополнительный вопрос: включает ли операция dynamic_cast копирование данных?

Спасибо :)

ИЗМЕНИТЬ:

Спасибо за все эти очень поучительные ответы.

Теперь скажем метод

bool isIsosceles()

реализован в треугольнике, но не в прямоугольнике.

Тогда сразу звоните

p->isIsosceles()

явно потерпит неудачу.

Моими первыми идеями были бы:

Объявите и реализуйте isIsosceles() как виртуальный метод в базовом классе Polygon как

virtual bool isIsosceles()
{ 
    cout << "Isosceles means nothing to me." << endl;
    exit(EXIT_FAILURE);
}

или использование dynamic_cast в операторе if.

Является ли какой-либо из этих вариантов хорошей практикой здесь?

Большое спасибо


person ultrahamster    schedule 04.09.2014    source источник
comment
Есть ли лучший способ сделать это? Да, используйте интеллектуальные указатели вместо того, чтобы самостоятельно управлять памятью с помощью new() и delete. Также я бы рекомендовал поместить этот код в назначенный фабричный класс, который отвечает за создание правильных типов.   -  person πάντα ῥεῖ    schedule 04.09.2014
comment
dynamic_cast не требует копирования данных, но включает использование информации о типе времени выполнения (RTTI). Это часто считается медленной операцией.   -  person YoungJohn    schedule 04.09.2014


Ответы (4)


Используется ли неявное понижение приведения с помощью нового ОК?

Здесь не происходит «понижения»: это прямое использование полиморфного поведения. Ваш Polygon * является указателем на базовый класс; ваш код построения создает объект, который абстрагирует реализацию за счет использования виртуальных функций-членов.

Он компилируется, но мне интересно, вызывается ли деструктор выбранного производного класса, чтобы определенные переменные были правильно освобождены.

При условии, что деструктор в базовом классе виртуальный (а он и должен быть) освобождение объекта через указатель базового класса сделает все правильно:

delete p;

Есть ли лучший способ сделать это?

Вы можете использовать std::unique_ptr<Polygon> для автоматизации процесса удаления Polygon объекта. Использование интеллектуального указателя уничтожит объект, когда указатель выйдет за пределы области видимости.

Включает ли операция dynamic_cast копирование данных?

Я предполагаю, что вы не используете здесь dynamic_cast, потому что Polygon объявляет виртуальные функции-члены для всех интересующих операций. Однако, когда вы выполняете dynamic_cast, копирование данных не происходит. Система проверяет, разрешено ли приведение, и либо дает вам правильный указатель приведения, либо возвращает nullptr.

person Sergey Kalinichenko    schedule 04.09.2014

Будет работать, если вы не забудете delete p, а деструктор Polygon будет virtual. Это жизненно важно.

Лучшая альтернатива — обернуть его умным указателем.

person Luchian Grigore    schedule 04.09.2014

Это не принижение. На самом деле вы используете здесь полиморфизм, то есть создаете объект некоторого производного типа, который вы будете использовать в качестве объекта их базового типа.

Вы можете сделать это, но, как и со всем, что вы выделяете с помощью new, используйте удаление. Еще одна вещь, которую следует отметить, это то, что вам нужен виртуальный деструктор в 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
}
person JBL    schedule 04.09.2014

Идея заключается в том, что мне нужно использовать определенные методы из производных классов, не зная, какой класс мне нужен, пока программа не запустится.

Такой вид противоречит цели полиморфизма, который позволяет вам выполнять операции БЕЗ знания того, с каким производным типом вы работаете.

Есть ли лучший способ сделать это?

Это зависит от того, чего вы на самом деле пытаетесь достичь в первую очередь. То, что вы показали, может быть реализовано, например, как часть фабрики классов. Но вы не показали, как вы используете эти объекты после их создания, так что трудно сказать, правильно вы делаете или нет.

Интересно, вызывается ли деструктор выбранного производного класса, чтобы определенные переменные были правильно освобождены.

Это произойдет только в том случае, если ~Polygon() будет объявлен как virtual.

включает ли операция dynamic_cast копирование данных?

Нет. dynamic_cast просто выполняет поиск во время выполнения, чтобы получить указатель на другой раздел VMT для того же объекта.

person Remy Lebeau    schedule 04.09.2014