2009-08-11 30 views
5

Giả sử tôi có hai lớp với các thành viên giống hệt nhau từ hai thư viện khác nhau:Đúc giữa các lớp đồng dư không liên quan

namespace A { 
    struct Point3D { 
    float x,y,z; 
    }; 
} 

namespace B { 
    struct Point3D { 
    float x,y,z; 
    }; 
} 

Khi tôi cố gắng cross-đúc, nó làm việc:

A::Point3D pa = {3,4,5}; 
B::Point3D* pb = (B::Point3D*)&pa; 
cout << pb->x << " " << pb->y << " " << pb->z << endl; 

Theo đó tình hình là thế này đảm bảo để làm việc? Luôn luôn? Xin lưu ý rằng nó sẽ là rất không mong muốn để chỉnh sửa một thư viện bên ngoài để thêm một pragma liên kết hoặc một cái gì đó như thế. Tôi đang sử dụng g ++ 4.3.2 trên Ubuntu 8.10.

+0

Nếu bạn có pa, tại sao là nó mà bạn cần pb? Vì bất cứ nơi nào bạn sẽ sử dụng pb chỉ đơn giản là có & pa. Tôi không chắc chắn tôi đang rõ ràng về lý do ... – ezpz

Trả lời

2

Nếu cấu trúc bạn đang sử dụng chỉ là dữ liệu và không có kế thừa được sử dụng, tôi nghĩ rằng nó luôn luôn hoạt động.

Miễn là chúng là POD, nó sẽ ổn. http://en.wikipedia.org/wiki/Plain_old_data_structures

Theo tiêu chuẩn (1.8.5)

"Trừ khi nó là một lĩnh bit- fi (9.6), một đối tượng có nguồn gốc nhất phải có khác không quy mô và sẽ chiếm một hoặc nhiều byte lưu trữ.Các lớp con lớp cơ sở có thể có kích thước bằng không. Một đối tượng của POD5) loại (3.9) sẽ chiếm các byte liền kề của bộ nhớ. "

Nếu họ chiếm byte tiếp giáp dung lượng lưu trữ và họ là những cấu trúc tương tự với tên khác nhau, một dàn diễn viên nên thành công

+0

Khi tôi đọc báo giá đó từ tiêu chuẩn, nó không loại trừ padding, hoặc đảm bảo rằng hai cấu trúc sẽ sử dụng padding giống hệt nhau. Tôi đồng ý, nó gần như chắc chắn sẽ hoạt động trong thực tế. – jalf

+0

Nếu cả hai cấu trúc được xác định giống nhau và trình biên dịch giống nhau thì phần đệm phải giống nhau. –

-2

Tôi biết chính xác nó sẽ không hoạt động:

  • cả struct có sự liên kết differen;
  • biên soạn với các tùy chọn khác nhau RTTI

thể có một số khác ...

+0

Từ http://en.wikipedia.org/wiki/RTTI: "RTTI chỉ có sẵn cho các lớp có tính đa hình, có nghĩa là chúng có ít nhất một phương pháp ảo." Mối lo ngại của bạn vẫn áp dụng cho POD? Trong điều kiện nào chúng có liên kết khác nhau? – Jann

+0

Nó không phải như vậy. Có loại từ khóa C++ - sẽ trả về mã định danh cho bất kỳ loại nào (bất kể việc sử dụng), vì vậy trình biên dịch cần phải nhúng đoạn nhỏ vào bất kỳ cấu trúc nào. Hơn nữa, chúng ta không biết cấu trúc này sẽ được sử dụng như thế nào bởi lập trình viên cuối cùng. Vì vậy, đối với từng trường hợp, chuyển đổi này sẽ đúng, nhưng đối với mảng có thể không thành công. – Dewfy

+0

trình biên dịch * không * nhúng bất kỳ thứ gì vào bất kỳ cấu trúc nào. Thật dễ dàng để xác minh điều này với sizeof(). Bạn có thể dễ dàng tạo cấu trúc kích thước 1. Nếu bạn tạo một cấu trúc rỗng, nó thậm chí có thể có kích thước 0 nếu nó được sử dụng như một lớp cơ sở. – jalf

0

Dòng này nên là:

B::Point3D* pb = (B::Point3D*)&pa; 

Lưu ý &. Tôi nghĩ rằng những gì bạn đang làm là một reinterpret_cast giữa hai con trỏ. Trong thực tế, bạn có thể reinterpret_cast bất kỳ loại con trỏ đến một loại khác, bất kể loại của hai con trỏ. Nhưng điều này không an toàn, và không di động.

Ví dụ,

int x = 5; 
double* y = reinterpret_cast<double*>(&x); 

Bạn chỉ cần đi với C-Style, Vì vậy, dòng thứ hai thực sự là tương đương với:

double* z = (double*)&x; 

Tôi chỉ ghét C-Style khi đúc vì bạn không thể nói mục đích của diễn viên từ một cái nhìn :)


Trong trường hợp này, được bảo đảm hoạt động?

Đây không phải là thực hiện truyền giữa các loại.Ví dụ:

int i = 5; 
float* f = reinterpret_cast<float*>(&i); 

Bây giờ f trỏ đến cùng một vị trí mà i trỏ đến. Vì vậy, không có chuyển đổi được thực hiện. Khi bạn dereference f, bạn sẽ nhận được một phao với cùng một biểu tượng nhị phân nhị phân của số nguyên i. Đó là bốn byte trên máy tính của tôi.

+0

reinterpret_cast sẽ là một ý tưởng tồi, vì nó về mặt kỹ thuật không được đảm bảo để dẫn đến một con trỏ đến cùng một địa chỉ. static_cast (static_cast ()) đảm bảo một con trỏ đến cùng một địa chỉ. – jalf

+0

Cảm ơn bạn đã sửa. – Jann

2

Nếu hai cấu trúc POD bắt đầu bằng cùng một chuỗi thành viên, tiêu chuẩn đảm bảo rằng bạn sẽ có thể truy cập chúng một cách tự do thông qua công đoàn. Bạn có thể lưu trữ A :: Point3D trong một công đoàn, và sau đó đọc từ thành viên B :: Point3D, miễn là bạn chỉ chạm vào các thành viên là một phần của chuỗi chung ban đầu. (do đó, nếu một cấu trúc chứa int, int, int, float và phần còn lại chứa int, int, int, int, bạn chỉ được phép truy cập vào ba int đầu tiên).

Vì vậy, điều đó có vẻ như một cách được đảm bảo trong đó mã của bạn sẽ hoạt động. Điều này cũng có nghĩa là tác vụ nên hoạt động, nhưng tôi không chắc liệu điều này có được nêu rõ trong tiêu chuẩn hay không.

Tất nhiên tất cả điều này giả định rằng cả hai cấu trúc được biên dịch với cùng một trình biên dịch để đảm bảo ABI giống nhau.

+0

+1: Điểm tuyệt vời. Nó sẽ là một trình biên dịch rất kỳ lạ đã quyết định để điều trị POD-struct khác nhau khi lồng nhau trong một công đoàn hay không. –

0

Sau đây là khá an toàn:

namespace A { 
    struct Point3D { 
    float x,y,z; 
    }; 
} 

namespace B { 
    typedef A::Point3D Point3D; 
} 

int main() { 
    A::Point3D a; 
    B::Point3D* b = &a; 

    return 0; 
} 
Các vấn đề liên quan