2011-12-16 21 views
41

Tôi đang gỡ lỗi chương trình C++ bằng GDB.Làm thế nào để xác định xem một đối tượng là một thể hiện của lớp C++ có nguồn gốc nhất định từ một con trỏ đến một lớp cơ sở trong GDB?

Tôi có con trỏ đến đối tượng của một lớp nhất định. Con trỏ được khai báo là một số lớp siêu được mở rộng bởi một số lớp con.

Không có trường nào trong đối tượng để chỉ định loại lớp chính xác của đối tượng này nhưng một số hàm ảo (ví dụ: bool is_xxx()) được định nghĩa để cho biết loại lớp khi chạy.

Có cách nào để cho biết loại lớp chính xác của một đối tượng trong GDB mà không cần gọi các chức năng ảo này. Việc gọi các hàm như vậy trong GDB có thể tạo ra kết quả khó hiểu khi chương trình đa luồng.

+0

Tôi không có gdb Wiz, nhưng bạn có thể có thể đi qua con trỏ v-bàn (đó là những gì cơ sở của bạn lớp con trỏ theo nghĩa đen chỉ đến) và giải quyết tên của các hàm. – selbie

+0

@selbie tư vấn v-table là chính xác những gì ptype không dưới mui xe nếu {set print object on} đang hoạt động, như Beta chỉ ra trong câu trả lời của mình –

Trả lời

2

Bạn không cần gọi hàm ảo, bạn chỉ có thể xem địa chỉ của hàm ảo hoặc vtable. Một cách khác là sử dụng RTTI

45

Sử dụng ptype. Nếu bạn sử dụng nó bằng cách riêng của mình, bạn sẽ có được kiểu được khai báo của con trỏ:

(gdb) ptype ptr 
type = class SuperClass { 
    // various members 
} * 

Để có được loại thực tế của các đối tượng được trỏ tới, đặt "đối tượng print" biến:

(gdb) set print object on 
(gdb) ptype ptr 
type = /* real type = DerivedClass * */ 
class SuperClass { 
    // various members 
} * 
+10

'ptype' không hoạt động đối với tôi (gdb 7.2). Sau khi 'set print object on', lớp được in bởi' p * ptr'. –

+1

@PerJohansson Nó cũng không làm việc cho tôi. Bạn có tìm thấy giải pháp tốt hơn không? –

+0

@PerJohansson 'ptype' hoạt động với tôi trên GDB 7.11 * sau khi * thực hiện' đặt đối tượng in trên ': http://stackoverflow.com/a/37054214/895245 –

12

On ptype hệ thống của tôi hoặc whatis cũng chỉ hiển thị rõ ràng.

(gdb) whatis pObject 
type = QObject * 

Nhưng in entry đầu tiên của vtable giúp tôi:

(gdb) p /a (*(void ***)pObject)[0] 
$4 = 0xb4b4cdf4 <QMessageBox::metaObject() const> 

Ở đây pObject chỉ vào một QMessageBox mà có nguồn gốc từ QObject. Điều này chỉ hoạt động nếu các điểm nhập vtable vào một phương thức được ghi đè bởi lớp dẫn xuất.

Xem thêm: Print C++ vtables using GDB

Edit: In ấn chỉ con trỏ đến vtable làm việc đáng tin cậy hơn (mặc dù sản lượng sử dụng tên đọc sai và không phải là quá dễ đọc):

(gdb) p /a (*(void ***)pObject) 
$5 = 0xb4af33a0 <_ZTV11QMessageBox+8> 
+0

[mục nhập thứ hai trong vtable] (http://stackoverflow.com/questions/5712808/understand-the-vtable-entries) trỏ vào 'type_info'. Điều này luôn luôn được overriden. – MSalters

6

GDB 7.11

Kể từ GDB 7.11, GCC 5.3.1, Ubuntu 16.04, chỉ thực hiện:

p *myBase 

trên một cái gì đó biên dịch với:

gcc -O0 -ggdb3 

có thể đủ vì nó đã cho thấy:

$1 = {_vptr.MyBase = 0x400c00 <vtable for MyDerived1+16>} 

nơi MyDerived1 là lớp có nguồn gốc hiện tại chúng tôi đang tìm kiếm.

Nhưng nếu bạn làm ngoài:

set print object on 

sản lượng thậm chí còn rõ ràng hơn và trông giống như:

$1 = (MyDerived1) {<MyBase> = {_vptr.MyBase = 0x400c00 <vtable for MyDerived1+16>}, <No data fields>} 

này cũng ảnh hưởng đến các lệnh khác như:

ptype myBase 

mà show :

type = /* real type = MyDerived1 * */ 
class MyBase { 
    public: 
    virtual int myMethod(void); 
} * 

thay vì:

type = class MyBase { 
    public: 
    virtual int myMethod(void); 
} * 

Trong trường hợp này, không có dấu hiệu của các loại có nguồn gốc mà không set print object on.

whatis bị ảnh hưởng tương tự như: chương trình

(gdb) whatis myBase 
type = MyBase * 
(gdb) set print object on 
(gdb) whatis myBase 
type = /* real type = MyDerived1 * */ 
MyBase * 

Test:

#include <iostream> 

class MyBase { 
    public: 
     virtual int myMethod() = 0; 
}; 

class MyDerived1 : public MyBase { 
    public: 
     virtual int myMethod() { return 1; } 
}; 

class MyDerived2 : public MyBase { 
    public: 
     virtual int myMethod() { return 2; } 
}; 

int main() { 
    MyBase *myBase; 
    MyDerived1 myDerived1; 
    MyDerived2 myDerived2; 
    myBase = &myDerived1; 
    std::cout << myBase->myMethod() << std::endl; 
    myBase = &myDerived2; 
    std::cout << myBase->myMethod() << std::endl; 
} 
Các vấn đề liên quan