输出基类和继承类的内存内容
Print out memory content for base and inherited class
我试图添加一个print()成员函数,该函数将输出对象的内存内容,如下所示:
#include <iostream>
#include <string>
class A {
public:
virtual std::string print() {
std::string s;
s.append(reinterpret_cast<char*>(this), 0, sizeof(A));
return s;
}
};
class B : public A {
public:
B() : a('a') {}
char a;
};
int main() {
A a;
B b;
std::cout << "A "" << a.print() << ""n";
std::cout << "B "" << b.print() << ""n";
return 0;
}
如何打印B的整个长度,上面的清单只打印B类的A部分。
要安全地做到这一点,您必须覆盖B的虚函数:
std::string print() override {
std::string s;
s.append(reinterpret_cast<char*>(this), 0, sizeof(B));
return s;
}
为什么?因为您不能确定A和B具有相同的地址(例如,如果有多个基类)。
如果您喜欢这样的转储函数,为了减少代码,您可以使用模板并在每次重写中调用模板。
使用模板化的非虚函数基。
template<class T> class PrintMe
{
public:
std::string print() const
{
std::string s;
s.append(reinterpret_cast<char*>(this), 0, sizeof(T));
return s;
};
};
class A: public PrintMe<A>
{
// whatever
};
class B: public PrintMe<B>
{
};
// and in code which uses it
std::cout << some_b.print();
本质上,规则是任何类,X
,需要打印自身的能力继承自PrintMe<X>
。
就我个人而言,我根本不会使用继承或将其作为类的成员函数,而是使用
template<class T> std::string print(const T &x)
{
std::string s;
s.append(reinterpret_cast<char*>(&x), 0, sizeof(x));
return s;
}
// and in some code which needs this
std::cout << print(some_b);
// or, more explicitly
std::cout << print<B>(some_b);
注意,这完全避免了虚函数分派,而是依赖于编译时所识别的对象类型。
如何打印B…的整个长度
你可以考虑在类层次结构中"链接"你的打印方法。
您的计划无法处理不可打印的值。我也没有看到"十六进制"转换。但是,假设您的转换为char*是您想要的……
class A {
public:
virtual std::string print() {
std::string s;
s.append(reinterpret_cast<char*>(this), 0, sizeof(A));
return s;
}
};
class B : public A {
public:
B() : a('a') {}
char a;
virtual std::string print() {
std::string s = A::print(); // get A contents
s.append(reinterpret_cast<char*>(this), 0, sizeof(B));
return s;
}
};
不测试。
同样,这些问题依赖于实现。
根据我的经验(几乎完全是用g++), B的实例包含A和B的所有数据(我认为A在前面,即较低的地址)。A的实例只有A的数据,并且不能告诉,也不知道任何关于任何派生类的信息。
如果在你的实现中,B拥有A和B的所有数据(很容易分辨,只需打印sizeof(A)和sizeof(B)并与期望进行比较),你不需要在B::print()中调用A::print()。
还要注意——如果任何一个类都使用容器,那么您希望打印的容器数据可能不在类实例的堆栈空间中。容器(vector、堆、列表等)使用堆。所以你可以在堆栈上找到指针,而在其他地方找到数据。
update——
这里是揭示部分g++实现细节的一个小尝试。
我的解释是,它表明B类实例在B类数据属性的前面(在较低的地址)包含a类实例的数据属性。B的大小是a的两倍
对于这段代码,我删除了虚拟关键字。Virtual以我期望的方式影响这些对象的大小。但是没有关键字,大小正是我对uint64_t的期望。8字节(A)和16字节(B)。 class A
{
public:
A() :
aData(0x3132333435363738)
{
}
~A(){ }
std::string dump()
{
std::stringstream ss;
ss << " this: " << &(*this);
ss << " aData: " << &aData << std::endl;
return(ss.str());
}
std::string show()
{
std::stringstream ss;
ss << std::hex << "0X" << aData << std::endl;
return ss.str();
}
uint64_t aData; // 8 bytes
};
class B : public A
{
public:
B() : bData(0x3837363534333231)
{
}
~B(){ }
uint64_t bData; // 8 bytes
std::string dump()
{
std::stringstream ss;
ss << " this: " << &(*this);
ss << " A::aData: " << &(A::aData) << " bData:" << &bData
<< std::endl;
return(ss.str());
}
std::string show()
{
std::stringstream ss;
ss << std::hex << "0x" << A::aData << " 0x" << bData
<< std::endl;
return ss.str();
}
};
int t405(void)
{
A a;
B b;
std::cout << "nsizeof(a): " << sizeof(a) << std::endl;
std::cout << "sizeof(b): " << sizeof(b) << std::endl;
std::cout << "ninstance a: " << &a << std::endl;
std::cout << "instance b: " << &b << std::endl;
std::cout << "ninstance a - aData: " << a.dump() << std::flush;
std::cout << "ninstance b - bData: " << b.dump() << std::flush;
std::cout << "ninstance a show(): " << a.show() << std::flush;
std::cout << "ninstance b show(): " << b.show() << std::flush;
return(0);
}
输出应该像这样:
sizeof(a): 8 sizeof(b): 16
instance a: 0x7ffe73f5b5d0 instance b: 0x7ffe73f5b5e0
instance a - aData: this: 0x7ffe73f5b5d0 aData: 0x7ffe73f5b5d0
instance b - bData: this: 0x7ffe73f5b5e0 A::aData: 0x7ffe73f5b5e0 bData:0x7ffe73f5b5e8
instance a show(): 0X3132333435363738
instance b show(): 0x3132333435363738 0x3837363534333231
首先可以#include <stdint.h>
现在你可以将你的对象转换为uint8_t,并通过for循环迭代它,(size = sizeof(object))。
通过printf:
将十六进制值打印到stdinprintf("%hu", val[i]);
- 如何通过带有指向基类的指针的删除运算符释放内存
- 在C++中,为什么仅包含与其基类实例的联合的派生类占用的内存多于联合的大小?
- 这是删除基类指针的内存泄漏吗,以及如何使其正确
- 通过指向非多态类型的基类的指针获取已分配内存的地址
- 使用派生类分配基类指针的内存
- 为什么在调用基类构造函数时会出现内存泄漏
- 我怎么知道基类对象的指针数组中元素的类型,它将为派生类分配内存
- 是否可以从现有基类动态分配派生类所需的额外内存
- 对相同基类的引用在内存中必须具有单独的偏移量
- 将内存分配给基类的对象时,是否也分配了派生类的内存
- 派生类的实例化是否为基类的私有成员分配内存
- 虚拟析构函数:如果基类动态分配内存,基类中是否需要它
- 如何使用malloc通过基类的指针为派生类的对象分配内存
- 继承下基类的OOPS内存分配
- Delete导致基类中的虚拟析构函数出现内存错误
- 为什么如果我删除指向基类的指针,我就会出现内存泄漏
- 为什么这不是内存泄漏?还是吗?删除不带虚拟析构函数的基类指针
- 从原始内存和类分析器推断基元类型
- 在不增加类内存的情况下,我可以为派生类中基类的成员别名吗
- 如何读取指向派生类的基类指针数组的内存布局