【发布时间】:2014-09-21 17:09:02
【问题描述】:
我希望能够获得多态对象的大小。目前我得到了这个:
struct Base {
virtual std::size_t size() const {
return sizeof(*this);
}
};
struct Derived : Base {
virtual std::size_t size() const {
return sizeof(*this);
}
};
这实际上是复制和粘贴。我想做得更好。假设我真的很讨厌宏,而 CRTP 似乎是唯一明智的方法。让我们试一试:
struct SizedBase {
virtual std::size_t size() const = 0;
};
template <typename Type>
struct Sized : virtual SizedBase {
std::size_t size() const override {
return sizeof(Type);
}
};
struct Base : Sized<Base> {};
struct Derived : Base, Sized<Derived> {};
这看起来好多了,但遗憾的是格式不正确:Derived 包含两个 最终覆盖器,分别用于来自 Base 和来自 Sized<Derived> 的 size()。我们可以通过继承通过Sized来解决这个问题:
struct SizedBase {
virtual std::size_t size() const = 0;
};
template <typename Type, typename... SizedBases>
struct Sized : virtual SizedBase, SizedBases... {
std::size_t size() const override {
return sizeof(Type);
}
};
struct Base : Sized<Base> {};
struct Derived : Sized<Derived, Base> {};
这按预期工作,但是在多重继承的情况下会有些混乱,并禁止更改基的可访问性/虚拟性。
那么,有没有更好的办法呢?
【问题讨论】:
-
一个宏看起来会比你在这里做的更干净和可读...
-
为什么需要尺寸?
-
@n.m.对于不存储已分配块大小并要求在释放时显式提供的自定义内存分配器。但这与问题无关,同样的问题代表除身份之外的任何多态类型属性(可以通过
typeid获得),例如类型名称(type_info::name()已损坏)或通过复制构造函数定义的clone()之类的东西。 -
我认为一个简单的解决方案是让
Base和Derive等不直接从Sized派生,而只是临时派生。例如。如果您在代码中的某个位置需要一个其类型派生自SizedBase的对象,则将其包装在一个中。这是否可能/有效取决于这些类型的移动构造函数的速度。 -
@dyp,这会起作用,但会添加另一个 vtable 指针。我只会存储大小。然而,这给了我一个想法:
struct SizedBase { virtual size_t size() const = 0; }; template <class T> struct Sized : SizedBase, T { template <class... Args> Sized(Args.. args) : T(args...) {} size_t size() const { return sizeof(*this); } }; template <class T, class... Args> T* get(Args... args) { return new (alloc.get(sizeof(Sized<T>))) Sized<T>(args...); } template <class T> void put(T* p) { size_t s = dynamic_cast<SizedBase*>(p)->size(); alloc.put(p, s); }当T是final时,这很遗憾地失败了。
标签: c++ polymorphism sizeof crtp