Для университетского задания я строю структуру классов, включающую, в частности, несколько классов Pixel
, каждый из которых использует определенное цветовое пространство (например, 8-битный GreyScale, 24-битный RGB и т. Д.).
Большая часть работы выполняется Image::Base&
, который будет использовать Pixel::Base&
s, поэтому не будет знать, какой конкретный тип Pixel
находится на каждой стороне любых Pixel
назначений.
Итак, чтобы разрешить преобразование между неопределенными подтипами, я использую конструкторы преобразования и operator=
через виртуальные функции из базового класса.Я видел два варианта: либо каждый класс должен реализовывать to_Grey8()
, to_RGB()
и т. Д. - сделать конструкторы преобразования и operator=
небольшими за счет наличия множества отдельных функций преобразования - или я получаю, что принимающий объект выполняетсамо преобразование (с обратными последствиями).
По какой-то причине я изначально выбрал второй вариант.
Проблема в том, что при преобразовании в RGB (например) требуется скопироватьвнутренние значения из другого объекта , если это тоже объект RGB, но он не может этого сделать, если другой объект просто Base&
, поэтому в результате я оказалсяиспользуя dynamic_cast
s для проверки - потенциально много из них по мере роста числа подтипов - для каждого отдельного типа Pixel
, который требует специальной обработки.
У меня такое ощущение, что этот подход может быть "плохим",Итак:
Это правильное / действительное / безопасное использование dynamic_cast
?
Если нет, то почему?И какова разумная альтернатива для достижения тех же целей?
Просто сосредоточив внимание на operator=()
, вот важные биты определений:
class Base
{
public:
virtual Pixel::Base& operator=( Pixel::Base const& rhs ) = 0;
}
class RGB24 : public Base
{
private:
unsigned char r, g, b;
public:
virtual Pixel::RGB24& operator=( Pixel::Base const& rhs );
}
class Grey8: public Base
{
private:
unsigned char i;
public:
virtual Pixel::Grey8& operator=( Pixel::Base const& rhs );
}
С реализациямивыглядит так:
Pixel::Grey8& Grey8::operator=( Pixel::Base const& rhs )
{
i = rhs.intensity();
return *this;
}
Pixel::RGB24& RGB24::operator=( Pixel::Base const& rhs )
{
try {
auto castrhs = dynamic_cast<Pixel::RGB24 const&>(rhs);
r = castrhs.r;
g = castrhs.g;
b = castrhs.b;
return *this;
} catch (std::bad_cast& e) {}
//TODO other casting blocks will go here as other Pixel classes are added
//no specific handler worked, so just effectively greyscale it
r = rhs.intensity();
g = rhs.intensity();
b = rhs.intensity();
return *this;
}