2010-01-24 34 views
8

Có cách nào để xem các hàm mặc định (ví dụ: hàm tạo bản sao mặc định, toán tử gán mặc định) được tạo bởi trình biên dịch như VC++ 2008 cho một lớp không xác định chúng?xem các chức năng mặc định được tạo bởi trình biên dịch?

+1

Dường như có một số nhầm lẫn về câu hỏi của bạn. Bạn có nghĩa là làm thế nào để tôi xem các nguyên mẫu chức năng, làm thế nào để tôi nhìn thấy được mặc định và tôi đã thực hiện, hoặc làm thế nào để tôi thấy mã cho việc triển khai mặc định? –

Trả lời

11

Với trình biên dịch clang, bạn có thể xem chúng bằng cách chuyển đối số -ast-dump. Clang vẫn đang trong giai đoạn phát triển, nhưng bạn đã có thể sử dụng nó cho những việc sau:

[[email protected] cpp]$ cat main1.cpp 
struct A { }; 
[[email protected] cpp]$ clang++ -cc1 -ast-dump main1.cpp 
typedef char *__builtin_va_list; 
struct A { 
public: 
    struct A; 
    inline A(); 
    inline A(struct A const &); 
    inline struct A &operator=(struct A const &); 
    inline void ~A(); 
}; 
[[email protected] cpp]$ 

Tôi hy vọng đó là những gì bạn yêu cầu. Hãy thay đổi mã và xem lại.

[[email protected] cpp]$ cat main1.cpp 
struct M { M(M&); }; 
struct A { M m; }; 
[[email protected] cpp]$ clang++ -cc1 -ast-dump main1.cpp 
typedef char *__builtin_va_list; 
struct M { 
public: 
    struct M; 
    M(struct M &); 
    inline struct M &operator=(struct M const &); 
    inline void ~M(); 
}; 
struct A { 
public: 
    struct A; 
    struct M m; 
    inline A(); 
    inline A(struct A &); 
    inline struct A &operator=(struct A const &); 
    inline void ~A(); 
}; 
[[email protected] cpp]$ 

Thông báo như thế nào copy constructor ngầm tuyên bố của A bây giờ có một số tài liệu tham khảo không const, bởi vì một trong những thành viên của nó có quá (thành viên m), và rằng M không có constructor mặc định tuyên bố.

Để nhận mã được tạo, bạn có thể để nó phát ra ngôn ngữ trung gian của máy ảo. Hãy xem mã được tạo cho điều này:

struct A { virtual void f(); int a; }; 
A f() { A a; a = A(); return a; } // using def-ctor, assignment and copy-ctor 

[[email protected] cpp]$ clang++ -cc1 -O1 -emit-llvm -o - main1.cpp | c++filt 
[ snippet ] 
define linkonce_odr void @A::A()(%struct.A* nocapture %this) nounwind align 2 { 
entry: 
    %0 = getelementptr inbounds %struct.A* %this, i32 0, i32 0 ; <i8***> [#uses=1] 
    store i8** getelementptr inbounds ([3 x i8*]* @vtable for A, i32 0, i32 2), i8*** %0 
    ret void 
} 

define linkonce_odr %struct.A* @A::operator=(A const&)(%struct.A* %this, 
    %struct.A* nocapture) nounwind align 2 { 
entry: 
    %tmp = getelementptr inbounds %struct.A* %this, i32 0, i32 1 ; <i32*> [#uses=1] 
    %tmp2 = getelementptr inbounds %struct.A* %0, i32 0, i32 1 ; <i32*> [#uses=1] 
    %tmp3 = load i32* %tmp2       ; <i32> [#uses=1] 
    store i32 %tmp3, i32* %tmp 
    ret %struct.A* %this 
} 

define linkonce_odr void @A::A(A const&)(%struct.A* nocapture %this, %struct.A* nocapture) 
    nounwind align 2 { 
entry: 
    %tmp = getelementptr inbounds %struct.A* %this, i32 0, i32 1 ; <i32*> [#uses=1] 
    %tmp2 = getelementptr inbounds %struct.A* %0, i32 0, i32 1 ; <i32*> [#uses=1] 
    %tmp3 = load i32* %tmp2       ; <i32> [#uses=1] 
    store i32 %tmp3, i32* %tmp 
    %1 = getelementptr inbounds %struct.A* %this, i32 0, i32 0 ; <i8***> [#uses=1] 
    store i8** getelementptr inbounds ([3 x i8*]* @vtable for A, i32 0, i32 2), i8*** %1 
    ret void 
} 

Bây giờ, tôi không hiểu ngôn ngữ trung gian (được xác định tại llvm.org). Nhưng bạn có thể dịch tất cả mã đó vào C bằng trình biên dịch llvm:

[[email protected] cpp]$ clang++ -cc1 -O1 -emit-llvm -o - main1.cpp | llc -march=c -o - | c++filt 
[snippet] 
void A::A()(struct l_struct.A *llvm_cbe_this) { 
    *((&llvm_cbe_this->field0)) = ((&_ZTV1A.array[((signed int)2u)])); 
    return; 
} 


struct l_struct.A *A::operator=(A const&)(struct l_struct.A *llvm_cbe_this, struct l_struct.A 
    *llvm_cbe_tmp__1) { 
    unsigned int llvm_cbe_tmp3; 

    llvm_cbe_tmp3 = *((&llvm_cbe_tmp__1->field1)); 
    *((&llvm_cbe_this->field1)) = llvm_cbe_tmp3; 
    return llvm_cbe_this; 
} 


void A::A(A const&)(struct l_struct.A *llvm_cbe_this, struct l_struct.A *llvm_cbe_tmp__2) { 
    unsigned int llvm_cbe_tmp3; 

    llvm_cbe_tmp3 = *((&llvm_cbe_tmp__2->field1)); 
    *((&llvm_cbe_this->field1)) = llvm_cbe_tmp3; 
    *((&llvm_cbe_this->field0)) = ((&_ZTV1A.array[((signed int)2u)])); 
    return; 
} 

Tada! Chú ý cách nó đặt con trỏ bảng ảo trong hàm tạo bản sao và hàm tạo mặc định. Hi vọng điêu nay co ich.

+0

Clang có thể chạy trên windows 7 không? Tôi không thể tìm thấy bất kỳ tải xuống cho các cửa sổ MS. – Southsouth

+0

Tại sao "struct A;" là một phần của mã được tạo trong các trường hợp sau đây struct A { public: struct A; inline A(); ... } Southsouth

0

Công cụ xem đối tượng (như objdump hoặc dumpbin) có thể tháo rời các tệp đối tượng đầu ra cho bạn. Sau đó, bạn có thể poke xung quanh và xem những gì hướng dẫn được nhận ra cho các chức năng/phương pháp mà bạn quan tâm.

7

Bạn có thể theo dõi mã bằng trình gỡ rối để xem điều gì đang diễn ra. Ví dụ:

#include <string> 

struct A { 
    int a[100]; 
    char c; 
    std::string s; 
}; 

int main() { 
    A a; 
    A b(a); 
} 

Đặt điểm ngắt khi xây dựng 'b' bởi hàm tạo bản sao. Đầu ra của trình lắp ráp tại điểm đó trong trình gỡ lỗi VC++ 6 là:

12:  A b(a); 
00401195 lea   eax,[ebp-1B0h] 
0040119B push  eax 
0040119C lea   ecx,[ebp-354h] 
004011A2 call  @ILT+140(A::A) (00401091) 

Cuối cùng là lệnh gọi hàm sao chép. Bạn cũng có thể theo dõi điều đó nếu bạn muốn biết thêm chi tiết. Tuy nhiên, nếu câu hỏi của bạn là "làm thế nào tôi có thể nhìn thấy mã C++ cho nhà xây dựng sao chép et al", câu trả lời là bạn không thể, bởi vì không có bất kỳ - trình biên dịch tạo ra bộ mã hóa hoặc mã máy (tùy thuộc vào tùy chọn này.). trên trình biên dịch của bạn) cho họ, không phải mã C++.

-1

Bạn có chắc chắn cần xem các chức năng này không?

Theo mặc định, Trình biên dịch tạo chúng bằng cách gọi toán tử Constructor hoặc Assignment trên mỗi biến thành viên.

Vấn đề với điều đó là khi bạn sử dụng các đối tượng sử dụng tham chiếu Đếm để quản lý dữ liệu, Trình tạo bản sao mặc định sẽ tạo bản sao của đối tượng chứ không phải bản sao của Dữ liệu mà đối tượng trỏ tới. Đây cũng là trường hợp cho con trỏ.Vì vậy, nếu bạn có một lớp học như:

class aClass 
{ 
    int one; 
    int *ptwo; 
}; 

Trình tạo bản sao mặc định chỉ sao chép dữ liệu a và con trỏ b. Tuy nhiên, anh ta không sao chép dữ liệu được chỉ ra bởi b. Nếu bạn sử dụng lớp học này như

aClass a, b; 
a.ptwo = new int; 
a.one = 1; 
*(a.ptwo) = 2; 

b = a; 

*(b.ptwo) = 1; 
//a.ptwo now points to an integer with the value of 1 

Nếu bạn muốn lớp này sao chép giá trị ptwo thay vì con trỏ, bạn sẽ cần chức năng điều hành gán bản sao của riêng bạn. Nếu bạn quan tâm đến chi tiết hơn những gì các chức năng mặc định làm và những gì không thì bạn hãy xem vào cuốn sách "Hiệu quả C + +".
Nó có toàn bộ một chương về công cụ này, giải thích những chức năng mặc định của lớp học, không làm, những gì họ nên làm, khi nào để viết của riêng bạn. Tôi chắc chắn bạn có thể tải phiên bản kỹ thuật số trên web nếu bạn chỉ muốn biết về chức năng này.

2

Trình biên dịch tạo ra các phương thức trừu tượng không tồn tại trong mã nguồn.
Hãy xem ví dụ bên dưới, tôi thử và giải thích những gì bốn phương thức tạo biên dịch có nghĩa vụ phải làm ở cấp mã nguồn. Từ đó bạn sẽ có thể ngoại suy bất kỳ lớp bình thường nào.

Nếu bạn có một lớp học như thế này:

class X: public Base 
{ 
    int* a; 
    double b; 
    Y  c; 
}; 

Sau đó trình biên dịch tạo ra tương đương với các nội dung sau:

X::X() // Default constructor 
    :Base() Calls the base class default constructor 
    //,a pointers are POD no default initialization 
    //,b double are POD no default initialization 
    ,c() //Call default constructor on each non POD member 
{} 

X::~X() // Default destructor 
{} 
// Destructor for each non POD member in reverse order 
~c()  calls the destructor of the class type 
//~b  double are POD no destructor 
//~a  pointers are POD no destructor 
~Base() // Calls the base class destructor 

X::X(X const& copy) 
    :Base(copy) // calls the base class copy constructor 
    // Copies each member using its copy constructor 
    ,a(copy.a)  // Pointers copied (Note just the pointer is copied, not what it points at) 
    ,b(copy.b)  // Double copied. 
    ,c(copy.c)  // Uses copy constructor of the class type (must be accessible) 
{} 

X& X::operator=(X const& copy) 
{ 
    Base::operator=(copy); // Calls the base class assignment operator 
    // Copies each member using the members assignment operator 
    a = copy.a; // Pointers copied (Note just the pointer is copied, not what it points at) 
    b = copy.b; // Double copied 
    c = copy.c; // Uses assignment operator of the class type (must be accessible) 

    return *this; 
} 
+0

Xem thêm: http://stackoverflow.com/a/1810320/14065 –

Các vấn đề liên quan