簡體   English   中英

打印出基類和繼承類的內存內容

[英]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();

本質上,規則是任何需要打印自身能力的類XPrintMe<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內部調用A :: print() ::打印()。

還要注意-如果任何一個類都使用容器,則您希望打印的容器數據可能不在類實例的堆棧空間中。 容器(向量,堆,列表等)使用堆。 因此,您將在堆棧上找到指針,並在其他位置找到數據。

更新-

這只是一個小嘗試,以揭示g ++實現細節的一部分。

我的解釋是,它表明B類實例在B類數據屬性的前面(較低地址)包含A類實例的數據屬性。 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

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

現在您可以將對象轉換為uint8_t,並通過for循環對其進行迭代(大小= sizeof(object))。

通過printf將其十六進制值打印到stdin:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM