0

Consider (note some code removed from object, i.e. constructors/destructors and some variables):

struct object {
    virtual bool object_is_solid() = 0;
    virtual bool object_is_visible() = 0;
    virtual bool object_is_persistent() = 0;
    virtual real_t object_depth() = 0;
    virtual real_t object_sprite_index() = 0;
    virtual real_t object_mask_index() = 0;

    struct object_properties {
      bool solid;
      bool visible;
      bool persistent;
      real_t depth;
      real_t sprite_index;
      real_t mask_index;
      real_t image_alpha;
      real_t image_angle;
      real_t image_blend;
      real_t image_index;
      real_t image_speed;
      real_t image_xscale;
      real_t image_yscale;
      real_t hfriction;
      real_t vfriction;
      real_t hgravity;
      real_t vgravity;
      real_t hspeed;
      real_t vspeed;
    } properties;

    void initialize_properties(object::object_properties& prop);
}

and

  object::object(unsigned long id, real_t x, real_t y)
    : id(id), xstart(x), ystart(y), x(x), y(y), xprevious(x), yprevious(y), properties{} {
    this->initialize_properties(this->properties);
  }

  void object::initialize_properties(object::object_properties& prop) {
    prop.solid = this->object_is_solid();
    prop.visible = this->object_is_visible();
    prop.persistent = this->object_is_persistent();
    prop.depth = this->object_depth();
    prop.sprite_index = this->object_sprite_index();
    prop.mask_index = this->object_mask_index();
    prop.image_alpha = 1;
    prop.image_speed = 1;
    prop.image_xscale = 1;
    prop.image_yscale = 1;
  }

Notice the usage of initialize_properties.

  1. Is this even safe? If I inline initialize_properties manually, clang refuses to compile it because it's calling pure virtual functions in the constructor.
  2. Is there a better way for me to initialise properties than what I am doing right now?
sth
  • 222,467
  • 53
  • 283
  • 367
kvanbere
  • 3,289
  • 3
  • 27
  • 52
  • It's fine. But why `initialize_properties` should be `inline`? It's a usual implementation detail - keep it in translation unit. Anyway, the architecture is a bit awkward, and requires redesign. Without knowing what you are trying to achieve, examples, and reasoning why you need these additional `bool` members - it's hard to give an answer. – Alexander Shukaev Dec 08 '13 at 09:17
  • Actually, from what I read in [this](http://stackoverflow.com/questions/8630160/call-to-pure-virtual-function-from-base-class-constructor) thread, it's unsafe. I guess I'm looking for alternatives then... – kvanbere Dec 08 '13 at 09:18
  • Haroogan: They are mutable and only set at construction to the "default" values for that kind of object. – kvanbere Dec 08 '13 at 09:18
  • Oh, you're calling them in constructor as well - yes, you better not do this. Another reason to redesign. – Alexander Shukaev Dec 08 '13 at 09:19
  • No, calling pure virtual functions in a constructor is always a bug (it will crash) and calling non-pure virtual functions in a constructor is nearly always a bug (it won't do what most novices expect it to do). – n. m. could be an AI Dec 08 '13 at 10:07

2 Answers2

1

Short answer: don't do it.

Explanation: When object is constructed, the object is of type object, not the derived class yet. Let's call the derived class my_object.

Any virtual function (pure or not) that your in object's constructor will call object's version. Only in the body of my_object::my_object() the object type is my_object, not before.

The solution is to separate construction from initialization. From my_object::my_object() call a virtual function Initialize or better, expose it as a public method so the code that created the my_object instance will call it to initialize the object.

Example:

my_object o;
o.Init(params);
egur
  • 7,830
  • 2
  • 27
  • 47
  • “The solution is to separate construction from initialization”: _A possible_ solution is ... (for example n.m. suggested another one (namely, CRTP) in a comment below) – gx_ Dec 08 '13 at 11:27
  • Calling static functions is very limiting and is CRTP more complex (code is less readable). In this case the desired outcome is a single base class. If the base class uses a template it can't be used with other variants of the template since they are completely different classes: `Base` and `Base` have nothing in common - e.g. can't be placed in a single container. – egur Dec 08 '13 at 12:17
0

No, it's not safe.

I'm going to refractor the code so that it's necessary the user call a member function to perform this initialisation. It's not as automatic as I'd like, but it's probably for the best.

kvanbere
  • 3,289
  • 3
  • 27
  • 52
  • 1
    You probably can keep things automatic if you use CRTP. Consider this code: `template class Base { ... }; class Myclass : public Base { ... };` Now `Base` can call *static* functions of `Derived` all day long, even in constructors. – n. m. could be an AI Dec 08 '13 at 10:21
  • Different types for a base class sort of miss the target. The various variants of `Base<>` are not related in any way - can't be used in lists, arrays, etc. together. – egur Dec 08 '13 at 12:19