2012-03-30 70 views
5

Ví dụ, tôi có một số hệ thống phân cấp lớp (có thể, với tất cả các loại thừa kế - công cộng, tư nhân, cộng đồng ảo, đa thừa kế, vv):Khi nào tôi có thể so sánh con trỏ với cùng một đối tượng trong C++?

class A { 
    int a; 
public: 
    virtual ~A() {} 
}; 

class B: public A { int b; }; 
class C: public virtual B { int c; }; 
class E: public virtual B { int e; }; 
class F: public C, public E { int f; }; 

Sử dụng dàn diễn viên tôi nhận được gợi ý cho mọi phụ đối tượng của đối tượng chính "lớn":

F * f = new F; 
E * e = f; 
C * c = f; 
B * b = f; 
A * a = f; 

Tôi có thể so sánh điểm nào của con trỏ này cho bình đẳng (operator ==) và tại sao? Liệu việc so sánh có sử dụng logic-logic hay một số kỹ thuật khác?

Các tình huống có thể xảy ra là gì, khi tôi không thể so sánh con trỏ với cùng một đối tượng phức tạp? Loại vật thể nào có thể là?

Tôi mong đợi, rằng tất cả các con trỏ đến cùng một đối tượng luôn bằng nhau.

+1

* Tại sao bạn muốn so sánh chúng, đó là câu hỏi . – Jon

+3

Con trỏ chỉ đơn thuần là địa chỉ, Nếu et tất cả những gì bạn muốn so sánh bất cứ thứ gì nó có thể là đối tượng được trỏ bởi con trỏ, Bạn không thể so sánh hai địa chỉ và cho biết các đối tượng ở các vị trí đó có bằng nhau hay không. .. nhưng điều đó thật sai. –

+0

@Als: Nếu tôi làm 'std :: cout << (e == b) <<" "<< e <<" "<< b << std :: endl;', nó in '1 0x1aaa020 0x1aaa030' . Vì vậy, các địa chỉ khác nhau, nhưng con trỏ là như nhau. Toàn bộ câu hỏi là về các quy tắc chung C++ của loại so sánh đó. –

Trả lời

3

Bạn có thể so sánh hai con trỏ nếu một loại con trỏ là mặc nhiên chuyển đổi thành khác ; có nghĩa là, nếu cả hai đều trỏ đến cùng một loại, hoặc một điểm đến một lớp cơ sở của người khác. Việc chuyển đổi sẽ thực hiện điều chỉnh cần thiết đến địa chỉ sao cho, nếu cả hai con trỏ trỏ tới cùng một đối tượng, chúng sẽ so sánh bằng nhau.

Trong trường hợp này, bạn có thể so sánh bất kỳ cặp nào trừ c == e, vì không phải C cũng không phải E có nguồn gốc từ loại kia. Để so sánh chúng, bạn sẽ cần phải chuyển đổi chéo, hoặc chuyển đổi cả hai thành lớp cơ sở chung của chúng; không phải những điều này có thể được thực hiện hoàn toàn.

Nhân tiện, không cần dynamic_cast trong mã của bạn, vì bạn đang truyền tới con trỏ lớp cơ sở và việc chuyển đổi an toàn có thể được thực hiện hoàn toàn.

3

Bạn phải cẩn thận ở đây. Ví dụ, c và e là con trỏ đến các khía cạnh riêng biệt của * f, và do đó không thực sự là cùng một đối tượng. May mắn thay trình biên dịch sẽ cung cấp cho bạn một lỗi nếu bạn cố gắng so sánh c và e bởi vì người ta không bắt nguồn từ người khác. Bất kỳ sự so sánh nào khác trong ví dụ của bạn sẽ hoạt động bởi vì một trong các con trỏ có thể được chuyển đổi một cách trivially thành loại khác.

class A { 
    int a; 
public: 
    virtual ~A() {} 
}; 

class B: public A { int b; }; 
class C: public virtual B { int c; }; 
class E: public virtual B { int e; }; 
class F: public C, public E { int f; }; 

{ 
    F * f = new F; 
    E * e = dynamic_cast<E*>(f); 
    C * c = dynamic_cast<C*>(f); 
    B * b = dynamic_cast<B*>(f); 
    A * a = dynamic_cast<A*>(f); 
    cerr << (a==b) << "\n"; // true 
    cerr << (a==c) << "\n"; // true 
    cerr << (a==e) << "\n"; // true 
    cerr << (a==f) << "\n"; // true 
    cerr << (b==c) << "\n"; // true 
    cerr << (b==e) << "\n"; // true 
    cerr << (b==f) << "\n"; // true 
    cerr << (c==e) << "\n"; // compile error 
    cerr << (c==f) << "\n"; // true 
    cerr << (e==f) << "\n"; // true 
} 
0

Bạn chỉ có thể so sánh con trỏ cùng loại. Tuy nhiên, bạn không phải lúc nào cũng cần một diễn viên rõ ràng để làm như vậy. Trong trường hợp đơn giản:

B * pB = new B(); 
A * pA = pB; 

if (pA == pB) {} //pB is implicitly cast to an A * 

Khi bạn nhận được đến các lớp học phức tạp hơn, bạn sẽ cần phải thêm rõ ràng phôi để

F * pF = new F(); 
C * pC = dynamic_cast<C *>(pF) 
A * pA1 = dynamic_cast<A *>(pF); 
A * pA2 = dynamic_cast<A *>(pC); 

//should all be true 
if (pF == dynamic_cast<F *>(pA)) {} 
if (pA1 == dynamic_cast<A *>(pF)) {} 
if (pA1 == pA2) {} 
1

Nói chung, để đảm bảo rằng hai con trỏ (có thể loại khác nhau) trỏ đến cùng một đối tượng, sử dụng

dynamic_cast<void*>(pointer1) == dynamic_cast<void*>(pointer2) 

Tất nhiên, cả hai loại con trỏ nên polimorphic để cung cấp đúng dynamic_cast

Nếu phân cấp lớp có một gốc đơn (có thể là ảo), có thể đưa cả hai nhà thơ vào con trỏ vào lớp gốc và sau đó so sánh hai kết quả (không có đúc động)

+0

@Konrad: Tại sao không có ý nghĩa? Nếu downcasting cho cả hai con trỏ yeld cùng một địa chỉ, sau đó họ trỏ đến cùng một đối tượng (và ngược lại). Nếu các kiểu con trỏ không chuyển đổi được với nhau (hoặc một số lớp gốc), tôi không biết cách nào khác để kiểm tra nó ngoại trừ dynamic_cast (mặc dù có thể nó không phải là câu hỏi của OP) .. – user396672

+0

@Konrad: kiểm tra mã của tôi rằng cả hai con trỏ1 và con trỏ2 (xuống) được gán cho hầu hết lớp dẫn xuất tham chiếu đến cùng một đối tượng (tôi không giả vờ rằng câu trả lời này đúng cho câu hỏi của OP) – user396672

+0

Sau khi đọc lên tiêu chuẩn (nhắc bởi câu hỏi mới của bạn) trở lại. Tôi không biết (và khá chắc chắn về điều ngược lại) rằng tiêu chuẩn đã đưa ra các điều khoản bổ sung cho (cv đủ điều kiện) 'void *' trong một 'dynamic_cast'. –

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