获取多态对象的大小
Get size of polymorphic object
我希望能够获得多态对象的大小。此刻我得到了这个:
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> {};
这是按预期工作的,但在多重继承的情况下会有些混乱,并禁止更改基的可访问性/虚拟性。
那么,有更好的方法吗?
并不是说任何人都应该真正使用它,而是。。。
template <typename>
struct None1 {};
template <typename>
struct None2 {};
template <typename T>
struct PrivateBase { using Tpriv = T; using Tprot = None1<T>; using Tpub = None2<T>; };
template <typename T>
struct ProtectedBase { using Tpriv = None1<T>; using Tprot = T; using Tpub = None2<T>; };
template <typename T>
struct PublicBase { using Tpriv = None1<T>; using Tprot = None2<T>; using Tpub = T; };
template <typename K>
struct TriBase : private K::Tpriv, protected K::Tprot, public K::Tpub {};
template <typename T, typename ... Bases>
struct Sized : private Bases::Tpriv..., protected Bases::Tprot..., public Bases::Tpub...
{
virtual size_t size() { return sizeof(T); }
};
struct Foo : Sized<Foo> {};
struct X{};
struct Y{};
struct Bar : Sized<Bar, PrivateBase<X>, ProtectedBase<Y>, PublicBase<Foo>> {};
int main ()
{
Bar b;
Foo* f = &b;
X* x = &b; // error : private base
Y* y = &b; // error : protected base
}
虚拟继承留给读者练习。
基类的顺序不会被保留,但无论如何都不应该依赖它。
一些对生产更友好的东西可以这样实现(这是一个粗略的草图):
#include <cstdlib>
#include <typeinfo>
#include <unordered_map>
#include <memory>
#include <iostream>
struct myinfo
{
size_t size;
// any other stuff
};
using TypeInfoRef = std::reference_wrapper<const std::type_info>;
struct Hasher
{
std::size_t operator()(TypeInfoRef code) const
{
return code.get().hash_code();
}
};
struct EqualTo
{
bool operator()(TypeInfoRef lhs, TypeInfoRef rhs) const
{
return lhs.get() == rhs.get();
}
};
static std::unordered_map<TypeInfoRef, myinfo, Hasher, EqualTo> typemap;
template <typename K>
struct typemap_initializer
{
typemap_initializer()
{
typemap[typeid(K)] = myinfo{sizeof(K)};
}
};
struct Base
{
virtual ~Base() {}
size_t size() { return typemap[typeid(*this)].size; }
template<typename K, typename... Arg>
friend K* alloc(Arg...);
private:
void* operator new(size_t sz) { return ::operator new(sz); }
};
template<typename K, typename... Arg>
K* alloc(Arg... arg)
{
static typemap_initializer<K> ti;
return new K(arg...);
}
struct Foo : Base {int a;};
struct Bar : Foo {int b; int c;};
int main ()
{
Foo* f = alloc<Foo>();
Bar* g = alloc<Bar>();
std::cout << f->size() << std::endl;
std::cout << g->size() << std::endl;
}
当然,人们会放弃熟悉的Foo* foo = new Foo
语法,但在无处不在的std::make_shared<>
时代,这并不是什么大问题。
相关文章:
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 通过switch和static_cast访问多态对象的运行时类型
- 如何查找哪个类对象位于数组的特定索引上(多态性)
- C++ 在堆栈中包含多态属性的类对象存储
- 转身多态对象
- 多态对象的数组
- C++ 多态模板类,模板类型对象的实例化
- 创建基类指针的向量并将派生类对象传递给它(多态性)
- C++多态性:有没有办法找到对象成员函数的地址?
- C++ 被此代码与多态性、指针和对象切片混淆
- 了解C++中多态对象的序列化
- 具有多态性的对象声明中的逗号
- 如何复制多态对象
- 使用多态性时在子对象之间进行转换?
- 多态性的面向对象方法
- 分配分配器为多态对象分配内存
- 将多态对象存储在unordered_set中
- 如何使用多态性将相同的操作应用于具有相同基类的不同对象的unordered_sets
- 使用数组对对象的编译时多态性是否可行?
- C++对象多态性问题