2011-09-13 17 views
6

Vì vậy, sau khi tìm kiếm rất nhiều câu trả lời cho câu hỏi của tôi, cuối cùng tôi đã từ bỏ các kỹ năng của Google.Định nghĩa lại typedef trong lớp dẫn xuất?

Tôi có một lớp cơ sở Cơ sở và một lớp dẫn xuất Có nguồn gốc. Tôi muốn ghi đè loại trong lớp Cơ sở với một trong các lớp Có nguồn gốc. Dưới đây là một ví dụ:

class Apple { 
public: 
    Apple() { } 

    // ... 

}; 

class Orange { 
public: 
    Orange() { } 

    // ... 

}; 

class Base { 
public: 
    typedef Apple fruit; 

    // ... 

    virtual fruit func() { return Apple(); } 
}; 

class Derived : public Base { 
public: 
    typedef Orange fruit; 

    // ... 

    fruit func() override { return Orange(); } // <-- Error C2555! 
}; 

Mã này không làm việc, và nó mang lại cho một

C2555 error ('Derived::func': overriding virtual function return type differs and is not covariant from 'Base::func'). 

Trên là một trong những giải pháp tôi đã cố gắng. Tôi cũng đã thử tạo một lớp lồng nhau ảo trong Base và được xác định lại trong Có nguồn gốc và cũng không biên dịch (cũng rất lộn xộn).

Tôi cũng không thể lấy được táo và cam từ lớp cơ sở cùng trở về con trỏ/tham chiếu đến lớp cha mẹ của họ trong cơ sởnguồn gốc. Tôi cần phải thể chất trở lại một thể hiện của đối tượng.

  1. Có cách nào tôi có thể khai báo typedefs trừu tượng không?
  2. Nếu không, có giải pháp nào khác có thể đạt được những gì tôi đang cố gắng thực hiện không?

Trả lời

6

Trước hết, nhìn vào cú pháp sau:

fruit func() override { return Orange(); } 

override là gì? Trong C++ 03, không có từ khóa như vậy. Nó chỉ có trong C++ 11. Vì vậy, hãy chắc chắn rằng bạn đang sử dụng một trình biên dịch mà biết về từ khóa này.

Thứ hai, trong lớp dẫn xuất, fruit thực sự là Orange. Xác định lại typedef không phải là một vấn đề. Vấn đề là, OrangeApple không phải là loại biến thể. Bắt nguồn từ cái khác sẽ làm cho chúng covariant. Trong trường hợp của bạn, bạn đã lấy được Orange từ Apple để làm cho nó hoạt động.

Lưu ý rằng bạn đã thay đổi loại trả về từ fruit thành fruit* hoặc fruit&.

class Orange : public Apple {}; //correct - your code will work 

class Apple : public Orange {}; //incorrect - your code will not work 

Ý tưởng được, trong lớp cơ sở, các kiểu trả về nên con trỏ/tham khảo loại cơ sở (đó là Apple), và trong lớp có nguồn gốc, kiểu trả về có thể con trỏ/tham khảo thuộc loại Apple hoặc bất kỳ lớp nào xuất phát từ nó.

Nhân tiện, điều này có hợp lý không? Phát sinh Orange từ Apple?

Thiết kế lớp học như thế nào?

class Fruit {}; 
class Apple : public Fruit {}; 
class Orange : public Fruit {}; 

class Base 
{ 
    virtual Fruit* f(); 
}; 

class Derived : public Base 
{ 
    virtual Fruit* f(); 
}; 

Không cần sử dụng typedef.

+0

Từ khóa 'override' giúp loại bỏ lỗi của con người (như lỗi chính tả) bằng cách kiểm tra trình biên dịch nếu hàm thực sự ghi đè bất kỳ phương thức cơ sở nào hay không. Về vấn đề này, tôi biết điều đó. Có cách nào tôi _could_ làm cho họ covariant mà không cần sử dụng con trỏ hoặc tài liệu tham khảo? – Zeenobit

+0

Vì vậy, tôi đoán không có giải pháp để thực hiện công việc này. Cảm ơn mọi người. Tôi sẽ cố gắng sử dụng một hệ thống phân cấp khác. – Zeenobit

0

Bạn không thể thực sự làm điều đó, nếu bạn có một đối tượng giá trị, bạn phải biết đó là loại đối tượng nào. (Đây là một trong những khác biệt chính giữa một ngôn ngữ được gõ tĩnh như C++ và các ngôn ngữ được gõ động như Ruby và Python.)

Có nhiều cách để giải quyết vấn đề này. Trước tiên, giả sử rằng AppleOragne có một lớp cơ sở chung được gọi là Fruit. Một giải pháp là phân bổ động đối tượng bằng cách sử dụng new và trả về một con trỏ Fruit.

Một giải pháp khác, thay vì trả lại một giá trị, chức năng của bạn có thể mất một con trỏ hoặc tham chiếu đến một trái cây mà nó sau đó có thể điền vào.

Tuy nhiên, một giải pháp khác là phải có một số loại đối tượng container nội bộ sẽ tổ chức hoặc là Apple hoặc Orange. Bằng cách đó bạn có thể trả lại.

1

Điều này không có ý nghĩa gì để bắt đầu. Một Derived sẽ có thể được sử dụng bất cứ nơi nào một Base dự kiến, vì vậy bạn sẽ có thể làm

Base *foo = new Base(); 
Apple x = foo->func(); // this is fine 

Base *bar = new Derived(); 
Apple y = foo->func(); // oops... 

Tôi nghĩ rằng bạn cần phải nhìn vào một thiết kế khác nhau. Không rõ mục tiêu của bạn ở đây là gì, nhưng tôi đoán bạn có thể muốn Base làm mẫu lớp với thông số mẫu là Fruit hoặc có thể bạn cần loại bỏ toàn bộ thừa kế.

0

Lỗi được báo cáo cho bạn biết tất cả những gì bạn cần. Điều đó có nghĩa là loại trả lại trong phương thức Derived cần phải được bắt nguồn từ kiểu trả về trong phương thức cơ sở.

Điều này là để nếu phương thức cơ sở được gọi là hầu như, đối tượng trả về có thể được xem như là phương thức trả về bởi phương thức cơ sở.

Thực ra, bạn cần trả về một con trỏ hoặc tham chiếu để thực hiện việc này.

Điều bạn cần làm là xác định lớp cơ sở mới Fruit và có AppleOrange lấy được từ đó.

Sau đó, hãy func() trả lại số Fruit*.

Điều đó sẽ khiến bạn gặp vấn đề khi đảm bảo rằng Fruit*delete 'd tại một thời điểm nào đó.

Với bối cảnh nhiều hơn một chút, tôi nghi ngờ rằng (có thể là mỏng) templating là giải pháp bạn đang sau, thay vì thừa kế.