2010-09-18 33 views
6

Tôi có một lớp cơ sởCách chính xác để thực hiện so sánh cho một lớp cơ sở là gì?

class Animal 

với các chức năng ảo tinh khiết, và một bộ các lớp thừa kế

class Monkey : public Animal 
class Snake : public Animal 

Tôi muốn thực hiện một thao tác so sánh do đó, nếu tôi gặp phải hai con trỏ đến Loài vật trong mã của tôi

Animal* animal1 
Animal* animal2 

Tôi có thể so sánh chúng với nhau. So sánh sẽ mang lại giá trị sai, nếu animal1 và animal2 có các lớp dẫn xuất khác nhau. Nếu chúng thuộc cùng một lớp dẫn xuất, thì đầu ra của toán tử so sánh sẽ được trả về.

Ai đó có thể chỉ cho tôi cách thực hiện tốt điều này không?

Trả lời

4

Chà, rất nhiều câu trả lời khác hoàn toàn không cần thiết. dynamic_cast- nó tồn tại, sử dụng nó.

class Animal { 
public: 
    virtual bool operator==(const Animal& other) = 0; 
    virtual ~Animal() = 0; 
}; 
template<class T> class AnimalComp : public Animal { 
public: 
    virtual bool operator==(const Animal& ref) const { 
     if (const T* self = dynamic_cast<const T*>(&ref)) { 
      return ((T*)this)->operator==(*self); 
     } 
     return false; 
    } 
    virtual bool operator!=(const Animal& ref) const { 
     if (const T* self = dynamic_cast<const T*>(&ref)) { 
      return ((T*)this)->operator!=(*self); 
     } 
     return true; 
    } 
}; 
class Monkey : public AnimalComp<Monkey> { 
public: 
    virtual bool operator==(const Monkey& other) const { 
     return false; 
    } 
    virtual bool operator!=(const Monkey& other) const { 
     return false; 
    } 
}; 
class Snake : public AnimalComp<Snake> { 
public: 
    virtual bool operator==(const Snake& other) const { 
     return false; 
    } 
    virtual bool operator!=(const Snake& other) const { 
     return false; 
    } 
}; 

Chỉnh sửa: Cúi trước khi triển khai tự động theo khuôn mẫu của tôi!

Chỉnh sửa chỉnh sửa: Một điều tôi đã làm là quên gắn thẻ chúng là const, điều đó sai với tôi. Tôi sẽ không xin lỗi vì không làm! = Như, hãy đối mặt với nó, thực hiện nó là một doddle tổng số.

Chỉnh sửa khác: Các chàng trai của Chúa Giêsu Kitô, đây không phải là ví dụ về cách viết! = Hoặc ==, đây là ví dụ về cách sử dụng CRTP.Nếu bạn không thích cách tôi chọn để triển khai! = Hoặc ==, bạn có thể kiện.

+0

Vâng, tốt hơn với người vận hành quá tải ==. – imaginaryboy

+0

Lỗi nhỏ mặc dù, cần phải là 'const monkey * p = dynamic_cast (& khác)' và 'return * this == * p' ... tham chiếu không thể chuyển đổi thành' bool'. – imaginaryboy

+0

@imaginaryboy: Vâng, tôi đã sửa nó thành một giải pháp tốt hơn nhiều. – Puppy

3

Vì không có thông tin kiểu tĩnh liên kết với hai con trỏ, bạn sẽ cần sử dụng RTTI. Bạn có thể so sánh kết quả của loại typeid operator để xác định xem các đối tượng có cùng loại hay không.

Cách khác là thêm ID loại của riêng bạn vào lớp Animal. Thêm một hàm ảo khác và có các lớp dẫn xuất trả về một cái gì đó nhận dạng duy nhất kiểu đó. Bạn có thể sử dụng một kiểu liệt kê, hoặc có thể là tên của kiểu như một chuỗi. Nếu bạn có thể sử dụng nó, tuy nhiên, RTTI sẽ là IMHO tốt hơn nhiều.

+0

+1. Ngoài ra - RTTI phát sinh một số chi phí thời gian chạy (rõ ràng), mặc dù không quá nhiều. Nếu ứng dụng của bạn có tấn các lớp và bạn chỉ cần RTTI chỉ trong một vài nơi, tôi sẽ đi với whooping giải pháp của riêng bạn bằng cách sử dụng một chức năng chuyên dụng để nhận dạng loại. Tuy nhiên, nếu việc sử dụng RTTI là phổ biến, bạn chắc chắn nên sử dụng nó bằng cách sử dụng phương pháp của riêng bạn. –

+1

Tôi nghĩ rằng công văn đôi có thể là một cách tốt hơn để làm điều này hơn bằng tay fiddling với 'std :: type_info' đối tượng. Bạn sẽ làm gì một khi bạn biết đó là loại phù hợp? Bạn vẫn sẽ phải đưa con trỏ tới con trỏ của lớp dẫn xuất. Và kể từ khi C++ thể thao chỉ RTTI tối thiểu, bạn có thể sẽ phải chuyển qua một loại. Và một chuyển đổi trên một loại thường là một dấu hiệu mạnh mẽ cho thấy ai đó đã sử dụng tốt hơn các chức năng 'ảo'. – sbi

+0

@sbi Đồng ý, thực sự. Tôi đã dành quá nhiều thời gian để bắt đầu lập trình "The Java Way" (tm). Nó rõ ràng đã ảnh hưởng đến C++ của tôi. –

4

Một cách để thực hiện điều này, là sử dụng hai công văn để phân biệt giữa 'cùng lớp' và 'lớp khác nhau':

class Monkey; 
class Snake; 

class Animal { 
public: 
    virtual bool compare_impl(const Animal*) const { return false; } 
    virtual bool compare_impl(const Monkey*) const { return false; } 
    virtual bool compare_impl(const Snake*) const { return false; } 
    virtual bool compare(const Animal* rhs) const =0; 
}; 

class Monkey : public Animal { 
private: 
    /* Override the default behaviour for two Monkeys */ 
    virtual bool compare_impl(const Monkey*) const { /* compare two Monkey's */ } 
public: 
    /* Let overload-resolution pick the compare_impl for Monkey and let virtual dispatch select the override in the dynamic type of rhs */ 
    virtual bool compare(const Animal* rhs) const { return rhs->compare_impl(this); } 
}; 

class Snake : public Animal { 
private: 
    /* Override the default behaviour for two Snakes */ 
    bool compare_impl(const Snake*) const { /* compare two Snakes */ } 
public: 
    /* Let overload-resolution pick the compare_impl for Monkey and let virtual dispatch select the override in the dynamic type of rhs */ 
    virtual bool compare(const Animal* rhs) const { return rhs->compare_impl(this); } 
}; 
+0

Bạn có thể giải thích chính xác dòng sử dụng Animal :: compare_impl hay không; có nghĩa? Cho đến nay, tôi đã thấy từ khóa "using" chỉ trong "using namespace foo" – Hans

+0

@Hans: Nó mang một định danh lớp cơ sở vào phạm vi của lớp dẫn xuất, ngăn cản quá tải lớp dẫn xuất từ ​​ẩn lớp cơ sở. – sbi

+0

Tuyên bố 'sử dụng' của anh ta đang làm hai việc: 1) thay đổi quyền truy cập của lớp cơ sở 'compare_impl' từ protected thành private, và 2) làm cho Animal :: compare_impl có thể truy cập được vì nó được ẩn bởi các khai báo' compare_impl' của lớp dẫn xuất . – imaginaryboy

0

Dưới đây là một mẹo nhỏ Tôi sử dụng (Tôi hy vọng nó có thể làm việc cho bạn quá). tôi thêm các phương pháp tin sau đây để động vật và ghi đè lên nó trong mỗi lớp được thừa kế (Tôi biết, đó là một chút rắc rối, nhưng nó là nhanh hơn so với RTTI)

class Animal { 
protected: 

virtual const void* signature() const 
{ 
    static bool dummy; 
    return &dummy; 
} 
... 
} 


class Monkey : public Animal { 
private: 
virtual const void* signature() const 
{ 
    static bool dummy; 
    return &dummy; 
} 
... 
} 

bây giờ để xem nếu 2 con trỏ (a, b) là của cùng lớp chỉ cần kiểm tra cho

a-> chữ ký() == b> chữ ký()

nó không thực sự là một giải pháp, đó là một thủ thuật, nhưng nó hoạt động chỉ với 2 các cuộc gọi phương thức ảo (1 cho mỗi con trỏ) vì vậy nó khá nhanh.

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