打印出 base 和 inherited class 的内存内容

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 的整个长度,上面的清单仅打印 class B 的 A 部分。

要安全地执行此操作,您必须重写 B 的虚函数:

std::string print() override {
    std::string s;
    s.append(reinterpret_cast<char*>(this), 0, sizeof(B));
    return s;
}

为什么?因为您不能确定 A 和 B 是否具有相同的地址(例如,是否会有 multiple base classes)。

如果您喜欢这种转储功能,为了减少代码,您可以使用模板并在每次覆盖时调用模板。

首先,你可以 #include <stdint.h>

现在您可以将对象转换为 uint8_t,并通过 for 循环迭代它,(size = sizeof(object))。

通过 printf 将其十六进制值打印到标准输入:

printf("%hu", val[i]);

How can I print the entire length of B...

您可能会考虑 'chaining' 您在 class 层次结构中的打印方法。

您的计划无法处理不可打印的值。我也没有看到 'hex' 转换。但是,假设您对 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 的数据,并且无法分辨,对任何派生的 classes 都一无所知。

如果在您的实现中,B 拥有所有 A 和 B 数据(很容易分辨,只需打印 sizeof(A) 和 sizeof(B) 并与预期进行比较。),则无需调用 A::print() 在 B::print() 内部。

另请注意 - 如果 class 使用容器,则您希望打印的容器数据可能不在 class 实例的堆栈 space 中。容器(vector、heap、list等)使用堆。所以你会在堆栈上找到指针,在其他地方找到数据。

更新 --

这里是一个小小的尝试,旨在揭示部分 g++ 实现细节。

我的解释是说明classB实例包含classA实例的数据属性在classB数据的前面(低位地址)属性。 B 是 A 的两倍。

对于这段代码,我删除了虚拟关键字。虚拟以我预期的方式影响这些对象的大小。但是没有关键字,大小正是我对 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

使用具有非虚函数的模板化基。

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();

基本上规则是任何 class、X 需要打印自身的能力继承自 PrintMe<X>.

就个人而言,我根本不会使用继承或将此作为 class 的成员函数,而是

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);

请注意,这完全避免了虚函数分派,而是依赖于在编译时识别的对象的类型。