使用基类指针查找派生类对象的大小
find size of derived class object using base class pointer
在不知道派生类对象类型的情况下,是否有可能使用基类指针来查找派生类对象的大小?
谢谢。
没有直接的方法,但是可以编写一个虚拟的size()
方法,子类可以实现。中间模板类可以自动完成这些繁琐的工作。
struct base {
virtual size_t size() const =0;
virtual ~base() { }
};
template<typename T>
struct intermediate : base {
virtual size_t size() const { return sizeof(T); }
};
struct derived : intermediate<derived>
{ };
这确实要求你的层次结构是多态的…然而,基于对象的动态类型而不是静态类型的请求行为是多态行为定义的一部分。因此,这不会在一般用例中添加v表,因为至少您可能已经有了虚析构函数。
这个特殊的实现将你的继承树限制在一个单一的层次,而没有进入多重继承[即,从derived
派生的类型将不会得到自己对size
的覆盖]。有一个稍微复杂一点的变体可以解决这个问题。
struct base { /*as before */ };
template<typename Derived, typename Base>
struct intermediate : Base {
virtual size_t size() const { return sizeof(Derived); }
};
struct derived : intermediate<derived, base>
{ };
struct further_derived : intermediate<further_derived, derived>
{ };
基本上,这将在层次结构的每个实际层之间插入一个intermediate
,每个层用适当的行为覆盖size
,并从实际的基类型派生。
//what you want
base >> derived
>> more_deriveder
>> most_derivedest
//what you get
base >> intermediate<derived, base>
>> derived >> intermediate<more_deriveder, derived>
>> more_deriveder >> intermediate<most_derivedest, more_deriveder>
>> most_derivedest
几个mixin类型库使用了这样的方案,这样mixin就可以被添加到现有的层次结构中,而不需要引入多重继承。就我个人而言,我很少使用超过一层的继承,所以我不会为增加复杂性而烦恼,但是您的情况可能会有所不同。
我不认为这可以做到,因为sizeof
在编译时类型上工作。可以在基类中定义一个虚拟的Size
函数,并为每个派生类重写它。
由于c++中缺乏反射,对于任意类来说,这通常是不可能的。不过也有一些变通办法。您可以像其他人建议的那样编写一个virtual size()方法。你也可以使用奇怪的循环模板模式,也就是从Register<T>
继承,但我不推荐它,vtable每个对象花费4字节,T的子类报告不正确的大小,纠正它会导致多重继承。
最好的方法是使用一个类来注册、存储和查询动态大小信息,而不修改你想要查询的类:
EDIT:事实证明,由于typeid
的语义不一致,它仍然需要带有虚表的类,参见注释。
#include <cstddef>
#include <exception>
#include <iostream>
#include <map>
#include <typeinfo>
using namespace std;
class ClassNotFoundException
: public exception
{};
class Register
{
public:
template <class T>
static void reg (T* = NULL)
{
// could add other qualifiers
v[&typeid(T)] = sizeof(T);
v[&typeid(const T)] = sizeof(T);
v[&typeid(T*)] = sizeof(T);
v[&typeid(const T*)] = sizeof(T);
}
template <class T>
static int getSize (const T& x)
{
const type_info* id = &typeid(x);
if( v.find(id) == v.end() ){
throw ClassNotFoundException();
}
return v[id];
}
template <class T>
static int getSize (T* x)
{
return getSize(*x);
}
template <class T>
static int getSize (const T* x)
{
return getSize(*x);
}
protected:
static map<const type_info*, int> v;
};
map<const type_info*, int> Register::v;
class A
{
public:
A () : x () {}
virtual ~A () {}
protected:
int x;
};
class B
: public A
{
public:
B() : y () {}
virtual ~B () {}
protected:
int y;
};
int main ()
{
Register::reg<A>();
Register::reg<B>();
A* a = new B();
const A* b = new B();
cout << Register::getSize(a) << endl;
cout << Register::getSize(b) << endl;
}
考虑到@Dennis Zickefoose的好答案,有一种情况,你可以实现多层继承,既不需要虚函数,也不需要在每层继承之间使用中间类,从而增加了复杂性。
当继承层次结构中的所有中间(非叶子)类都是抽象类时,也就是说,它们没有被实例化。
如果是这种情况,您可以编写非叶抽象类模板化(再次)派生的具体类型。
下面的例子演示了这一点:
template <class TDerived>
class Shape // Base
{
public:
float centerX;
float centerY;
int getSize()
{ return sizeof(TDerived); }
void demo()
{
std::cout
<< static_cast<TDerived*>(this)->getSize()
<< std::endl;
}
};
class Circle : public Shape<Circle>
{
public:
float radius;
};
class Square : public Shape<Square>
{
// other data...
};
template <class TDerived>
class Shape3D : public Shape<TDerived>
// Note that this class provides the underlying class the template argument
// it receives itself, and note that Shape3D is (at least conceptually)
// abstract because we can't directly instantiate it without providing it
// the concrete type we want, and because we shouldn't.
{
public:
float centerZ;
};
class Cube : public Shape3D<Cube>
{
// other data...
};
class Polyhedron : public Shape3D<Polyhedron>
{
public:
typedef float Point3D[3];
int numPoints;
Point3D points[MAX_POINTS];
int getSize() // override the polymorphic function
{ return sizeof(numPoints) + numPoints * sizeof(Point3D); }
// This is for demonstration only. In real cases, care must be taken about memory alignment issues to correctly determine the size of Polyhedron.
};
示例用法:
Circle c;
c.demo();
Polyhedron p;
p.numPoints = 4;
p.demo();
- 如何使用单独文件中的派生类访问友元函数对象
- 使用基类指针创建对象时,缺少派生类析构函数
- 为什么此派生对象无法访问基类的后递减方法?
- 将带有派生模板的对象传递给接受具有基本模板的对象的功能
- 放置派生C++的新基子对象
- 在 C++ 中将对象转换为派生类型
- 链表包含 c++ 中不同的派生类对象
- 如何在不使用指针的情况下将派生类的对象作为参数传递给基类中的函数?
- 如何在新的派生对象中获取基本对象的数据?
- 如何将成员函数作为参数传递并在派生对象上执行方法列表
- 获取我的基类以递增派生类对象整数
- 派生类中的对象
- 在没有默认构造函数的情况下创建的派生对象
- OOP 标识派生对象
- 如何创建派生对象的向量?
- 按基类对象访问派生类资源时出错
- 将基类分配给派生对象,反之亦然,以C++以及静态和动态对象之间的差异
- static_cast将此对象派生到C++中的基类
- 如何在构造函数完成后立即销毁从 QWindow 对象派生的内容
- 我可以判断std::type_info对象是否等于另一个对象或从另一个对象派生的类吗?