我要求必须将自己派生类的某些对象系列在特殊的内存插槽中使用new运算符进行初始化。 所有这些都将来自共同基础。 问题是这种对象有大小限制。 因此,我想将静态断言放在派生对象的大小上,但我不想在每个后代中都打扰静态断言。 我的问题是:是否有任何方法可以将此断言放入基础或使用任何其他技巧来检查派生类声明之外的大小? 将基类设计为模板是可以接受的。

#1楼 票数:4

听起来像是CRTP的另一个用例:

constexpr std::size_t limit = 42;

template <typename Derived>
class Base {
  ~Base() {
    static_assert(sizeof(Derived) <= limit, "Derived class is too big.");
  }
};

class Foo : Base<Foo> {};

当然,如果您需要一个公共基类,则可以在CRTP大小检查下面注入一个基类:

class Base {
  // ...
};

constexpr std::size_t limit = 42;

template <typename Derived>
class SizeCheck : public Base {
  ~SizeCheck() {
    static_assert(sizeof(Derived) <= limit, "Derived class is too big.");
  }
};

class Foo : SizeCheck<Foo> {};

如果您的目标不仅是节省一些击键,而且是为了防御那些积极尝试破坏支票的人,请执行以下操作:

template <typename>
class SizeCheck;

class Base {
  // ...
private:
  // Only allow SizeCheck to derive from Base
  ~Base() = default;
  template <typename>
  friend class SizeCheck;
};

constexpr std::size_t limit = 42;

template <typename Derived>
class SizeCheck : public Base {
private:
  // Only allow Derived to derive from SizeCheck<Derived>
  friend Derived;
  ~SizeCheck() {
    static_assert(sizeof(Derived) <= limit, "Derived class is too big.");

    // Ensure that Derived is actually derived from SizeCheck
    static_assert(std::is_base_of<SizeCheck, Derived>(),
                  "Parameter to SizeCheck must be derived from SizeCheck.");

    // Require Derived to be final so that no one can sidestep 
    // the size check. (Uses C++14 std::is_final)
    static_assert(std::is_final<Derived>(),
                  "Nice try; parameter to SizeCheck must be final.");
  }
};

这一切都变得有点扭曲。 Base派生的类的大小并不是真正的问题,它有可能试图将太大的对象放入静态大小的缓冲区中。 通过保护缓冲区而不是限制派生类( DEMO ),从另一端解决问题可能更简单:

struct placement_delete {
  template <typename T>
  void operator()(T* ptr) {
    ptr->~T();
  }
};

template <typename T>
using placement_ptr = std::unique_ptr<T, placement_delete>;

class Base {
  // ...
};

template <std::size_t N, std::size_t Align = 0>
class buffer {
public:
  template <typename T, typename...Args>
  placement_ptr<T> emplace(Args&&...args) {
    static_assert(std::is_base_of<Base, T>(),
                  "Only classes derived from Base can go in a buffer.");
    static_assert(sizeof(T) <= sizeof(space_),
                  "Type is too big for buffer.");
    static_assert(alignof(decltype(space_)) % alignof(T) == 0,
                  "Buffer alignment is insufficient for type.");
    return placement_ptr<T>{::new(&space_) T(std::forward<Args>(args)...)};
  }
private:
  typename std::conditional<!Align,
    typename std::aligned_storage<N>::type,
    typename std::aligned_storage<N, Align>::type
  >::type space_;
};

#2楼 票数:2

基类无法直接知道派生类的大小-为此,需要知道派生类的内容和数据布局,这将要求该类位于同一编译单元中-并且您可能需要使用模板或宏来确保它发生。

您可以覆盖基类的operator new -这也将适用于所有本身不覆盖operator new派生类。 有多种方法可以找到,例如使用返回sizeof(*this)的虚函数(但这要求对象已创建-您不能从构造函数或构造之前调用它,因此如果需要使用新的展示位置,将无法正常工作)。

当然,如果您可以控制源代码,则可以执行static_assert(sizeof(someDerivedClass) > some_value) -但这并不保证不会被希望这样做的人破坏。

  ask by ardabro translate from so

未解决问题?本站智能推荐:

3回复

基类可以知道派生类是否重写了虚拟方法吗?

对于C#存在相同的问题,但不适用于C ++。
2回复

C ++中基类对象和派生类对象的大小

我使用上面的代码打印出基类和派生类的大小。 我在64位机器上运行代码。 我的电脑输出是 我还尝试使用sizeof(int)打印出int的大小,它是4。 我有以下问题: 对于Base1类的大小,它应该包含指向vtable的vptr和一个整数data1。 为什么它的大
5回复

设计问题,基类知道其派生

基本上,我有一个名为Geometry的基类,以及一些派生类,例如Point , Polygon等。 Geometry实现了这样的方法交集: 当我计算在我的程序两个几何的交集,我获得Geometry* ,我可以dynamic_cast它不管它确实是。 这是一个好的设计吗? 我
4回复

使用基类指针查找派生类对象的大小

当您不知道派生类型时,是否可以使用基类指针找到派生类对象的大小。 谢谢。
2回复

引用派生类时基类的对象大小

为什么在这种情况下sizeof函数返回 4? 从我的立场来看,指针ob指向一个已经创建的派生类xyz的对象d ,其大小为 20。所以sizeof(*ob)也应该返回这个值:20。
1回复

比较2个基类的派生对象

我有这样的事情: 我收到错误消息: 不允许输入类型名称 我知道不应该比较像这样的对象,但是我不知道该怎么做。
5回复

派生类对象是否包含基类对象?

请考虑以下示例代码: 问题 创建d1obj时, d1obj派生顺序调用构造函数:首先调用基类构造函数,然后再调用派生类构造函数。 这样做是由于以下原因: In-order to construct the derived class object the base class
5回复

从基类下载时,是否可以调用派生对象的虚方法?

给定以下类结构: ..和这段代码: ..输出将是“基本消息!”。 有没有办法转换或操纵对象,以使Derived的outputMessage方法版本被多态调用? 编辑 :我将尝试说明我之后的原因: 我正在编写挂钩到我们主系统的迁移工具。 出于这个原因,我需要访问