У меня есть базовый класс Image с членами поля const:
class Image {
protected:
const int width;
const int height;
public:
virtual ~Image();
const int getWidth() const;
const int getHeight() const;
protected:
Image(const int width, const int height);
};
Это означает, что в конструкторе я должен инициализировать ширину и высоту в списке инициализации следующим образом:
Image::Image(const int width, const int height) :
width(width), height(height) {
}
Теперь я намереваюсь сделать это подклассом так, чтобы я мог загрузить изображение, указав путь к подклассу (так что вызывающему коду не нужно беспокоиться о загрузке изображения). Этот класс будет выглядеть примерно так:
class GlImage: public Image {
private:
const GLuint textureId;
const int textureWidth; // power of 2 width
const int textureHeight; // power of 2 height
const double textureCoordinateX;
const double textureCoordinateY;
public:
GlImage(const string path); // is this constructor possible?
virtual ~GlImage();
const double getTextureCoordinateX() const;
const double getTextureCoordinateY() const;
private:
// what do we use for initialization functions?
};
Тем не менее, мы можем видеть здесь, что
— изображение должно быть загружено, прежде чем мы сможем получить ширину / высоту
— в подклассе есть поля, которые также должны быть инициализированы в списке инициализации
Как настроить конструктор подкласса так, чтобы все эти поля могли быть инициализированы?
Невозможно ввести другой объект в подкласс, который захватывает все данные поля, загрузить его как первый объект в списке инициализации и повторно извлечь значения для всех других полей, так как базовому классу нужна ширина / высота (которые недоступны, если логика загрузки изображения находится в производном классе).
Является ли единственным выходом удалить модификаторы const и инициализировать поля в конструкторе?
Проблема в том, что вы не можете вызвать конструктор базового класса из списка инициализатора ctor производного класса, так как вы не знаете размеры, верно?
Почему бы вам не создать статический метод в производном классе?
class GlImage: public Image {
....
static GlImage LoadFromFile(const string& path)
{
// read image data and other info
int w = ...
int h = ...
return GlImage(w, h, ....)
// of course, you would need a different ctor in derived class
// it can even be private
}
}
Вы можете использовать делегирующий конструктор с изменяемым вспомогательным объектом, который выполняет загрузку:
class GlImage: public Image {
...
GlImage(const string& path) : GlImage(GlImageLoader(path))
{
}
private:
struct GlImageLoader {
int w;
int h;
GlImageLoader(const string& path) {
//Read image data
w = ...;
h = ...;
}
};
GlImage(GlImageLoader&& l) : Image(l.w, l.h), textureId(l.textureId), ...
{
}
};