【问题标题】:Is setting substruct values to values returned by pure virtual functions safe in an object constructor?在对象构造函数中将子结构值设置为纯虚函数返回的值是否安全?
【发布时间】:2013-12-25 10:40:06
【问题描述】:

考虑(注意从object 中删除的一些代码,即构造函数/析构函数和一些变量):

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);
}

  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;
  }

注意initialize_properties的用法。

  1. 这还安全吗?如果我手动内联initialize_properties,clang 拒绝编译它,因为它在构造函数中调用纯虚函数。
  2. 有没有比我现在做的更好的方法来初始化properties

【问题讨论】:

  • 没关系。但是为什么initialize_properties 应该是inline?这是一个常见的实现细节 - 将其保存在翻译单元中。无论如何,架构有点尴尬,需要重新设计。在不知道您要达到的目标、示例以及为什么需要这些额外的 bool 成员的情况下 - 很难给出答案。
  • 实际上,从我在this 线程中读到的内容来看,这是不安全的。我想我正在寻找替代品......
  • Haroogan:它们是可变的,仅在构造时设置为那种对象的“默认”值。
  • 哦,你也在构造函数中调用它们——是的,你最好不要这样做。重新设计的另一个原因。
  • 不,在构造函数中调用纯虚函数总是一个错误(它会崩溃),在构造函数中调用非纯虚函数几乎总是一个错误(它不会像大多数新手那样期待它这样做)。

标签: c++ virtual-functions


【解决方案1】:

不,这不安全。

我将重构代码,以便用户调用成员函数来执行此初始化。它不像我想要的那样自动,但它可能是最好的。

【讨论】:

  • 如果您使用 CRTP,您可能可以保持自动化。考虑以下代码:template <class Derived> class Base { ... }; class Myclass : public Base<Myclass> { ... }; 现在Base 可以整天调用Derived静态 函数,即使在构造函数中也是如此。
  • 基类的不同类型会错过目标。 Base<> 的各种变体没有任何关系——不能在列表、数组等中一起使用。
【解决方案2】:

简短的回答:不要这样做。

说明: 构造object 时,对象的类型为object,还不是派生类。让我们调用派生类my_object

您的 in 对象的构造函数将调用对象的版本的任何虚函数(纯或非纯)。 只有在my_object::my_object() 的主体中,对象类型是my_object,而不是之前。

解决方案是将构造与初始化分开。 从my_object::my_object() 调用虚函数 Initialize 或更好,将其公开为公共方法,以便创建 my_object 实例的代码调用它来初始化对象。

例子:

my_object o;
o.Init(params);

【讨论】:

  • “解决方案是将构造与初始化分开”:一种可能的解决方案是......(例如,nm 在下面的评论中建议了另一种(即 CRTP))
  • 调用静态函数非常有限,并且 CRTP 更复杂(代码可读性较差)。在这种情况下,期望的结果是单个基类。如果基类使用模板,则它不能与模板的其他变体一起使用,因为它们是完全不同的类:Base<FooClass>Base<BarClass> 没有任何共同点 - 例如。不能放在一个容器中。
猜你喜欢
  • 1970-01-01
  • 2012-08-07
  • 1970-01-01
  • 1970-01-01
  • 2014-02-13
  • 1970-01-01
  • 2021-10-20
  • 1970-01-01
  • 2011-10-14
相关资源
最近更新 更多