Вызов функции инициализации, чьи эффекты необходимы для списка инициализации?

У меня есть базовый класс 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 и инициализировать поля в конструкторе?

2

Решение

Проблема в том, что вы не можете вызвать конструктор базового класса из списка инициализатора 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
}
}
1

Другие решения

Вы можете использовать делегирующий конструктор с изменяемым вспомогательным объектом, который выполняет загрузку:

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), ...
{
}
};
0

По вопросам рекламы [email protected]