Reputation: 386
I have a base Image class with const field members:
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);
};
This means in the constructor, I have to initialize the width and height in the initialization list like so:
Image::Image(const int width, const int height) :
width(width), height(height) {
}
Now I intend to subclass this such that I can load an image by providing the filepath to the subclass (so calling code does not have to worry about loading the image). This class would look similar to the following:
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?
};
However, we can see here that - the image has to be loaded before we can obtain the width/height - there are fields in the subclass that need to be initialized in the initialization list as well
How can the constructor of the subclass be set up such that all of these fields can be initialized?
It's not possible to introduce another object in the subclass which captures all of the field data, load this as the first object in the initialization list, and re-extract the values out for all the other fields as the base class needs the width/height (which aren't available if the image loading logic is in the derived class).
Is the only way out to remove the const modifiers and initialize the fields in the constructor?
Upvotes: 2
Views: 144
Reputation: 40603
You could use a delegating constructor with a mutable auxiliary object that does the loading:
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), ...
{
}
};
Upvotes: 0
Reputation: 14581
The problem is that you can't call a base class constructor from derived class ctor initializer list, as you don't know the dimensions, right?
Why don't you create a static method on derived class?
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
}
}
Upvotes: 1