2010-05-04 23 views
5

Làm thế nào tôi có thể thực hiện giao diện thông thạo này trong C++:Làm thế nào để thực hiện giao diện thông thạo với một lớp cơ sở, trong C++

class Base { 
public: 
    Base& add(int x) { 
    return *this; 
    } 
} 

class Derived : public Base { 
public: 
    Derived& minus(int x) { 
    return *this; 
    } 
} 

Derived d; 
d.add(1).minus(2).add(3).minus(4); 

mã hiện không hoạt động kể từ khi cơ sở lớp không biết gì về lớp Derived, vv Tôi sẽ rất biết ơn cho một gợi ý/gợi ý.

+0

Tại sao bạn làm điều này? Cơ sở có đại diện cho một cơ sở đa hình thực sự hay không - nếu nó không phải là một vi phạm LSP có lẽ là lý do tại sao nó là khó khăn. – Stewart

+1

@Stewart - nó không phải là một vi phạm LSP trừ khi đi qua một Derived off như là một cơ sở cho một chức năng mong đợi một cơ sở đã không hoạt động một cách thích hợp. Thêm hành vi mới vào các lớp con là hoàn toàn tốt và sẽ không bao giờ vi phạm LSP. Nó chỉ có thể vi phạm LSP bằng cách ghi đè hành vi hiện có trong Base sao cho nó không tuân theo giao diện nữa. –

Trả lời

10

Làm cho lớp cơ sở được tô điểm. Sử dụng các loại truy nã trở lại của cơ sở mẫu loại, như thế này:

template <typename T> 
class Base { 
public: 
    T& add(int x) { 
    return *static_cast<T *>(this); 
    } 
} 

Sau đó, thừa kế Xuất phát từ cơ sở như thế này:

class Derived : public Base<Derived> 

Ngoài ra (như là một câu trả lời cho Noah của bình luận), nếu bạn don' t muốn thay đổi Base, bạn có thể sử dụng một lớp trung gian thực hiện các công đúc, như thế này:

template <typename T> 
class Intermediate : public Base { 
public: 
    T& add(int x) { 
    Base::add(x); 
    return *static_cast<T *>(this); 
    } 
} 

Và chúng ta hãy kế thừa nguồn gốc từ trung cấp:

class Derived : public Intermediate<Derived> 
+2

+1. Điều này còn được gọi là Mẫu Định kỳ tò mò định kỳ: http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern – tzaman

+1

Lưu ý rằng bất kỳ hàm nào hoạt động trên cơ sở sẽ phải được chuyển thành một hàm mẫu nếu bạn làm điều này. –

+0

@Noah, tôi đã thêm một giải pháp thay thế nơi Cơ sở không bị thay đổi. – Patrick

1

Giao diện này không thể thực hiện trong C++. Bạn phải tạo ra hàm trừ() một hàm ảo bên trong Base hoặc sử dụng các hàm không phải thành viên để thực hiện một số dạng phát hiện kiểu.

Không kéo trừ trừ() trừ khi có ý nghĩa về mặt cơ sở.

+2

-1 Thật khó để nói rằng một cái gì đó là không thể trong C++ ;-) –

1

Vấn đề là về chức năng của bạn

Base& add(int x); 

này cũng tương tự như các nhà điều hành + =(), mà cũng phải được ghi đè để làm việc liền mạch.

Bạn cần ghi đè hàm này trên lớp dẫn xuất.

class Derived : public Base { 
public: 
    Derived& minus(int x) { 
    return *this; 
    } 
    Derived & add(int x) { 
    return static_cast<Derived &>(this->Base::add(x)); 
    } 
} 

theo cách này d.add (1) sẽ trả về tham chiếu đến d.

+0

và nếu tôi có 15 lớp học có nguồn gốc, tôi phải ghi đè lên add() trong mỗi một trong số chúng? nếu tôi thay đổi Base một ngày nào đó, tôi phải nhớ ai xuất phát từ nó? – yegor256

+0

Bạn nói đúng, nhưng trình biên dịch sẽ gọi lại cho bạn. Nếu bạn có thể thay đổi cơ sở sử dụng CRTP như đề xuất trên câu trả lời được chấp nhận, bạn tránh nó. Nhưng điều này không phải luôn luôn mong muốn hoặc có thể (nếu bạn không sở hữu Cơ sở, ví dụ). Hãy xem xét rằng bây giờ tất cả các chức năng trong Cơ sở sẽ được nhân đôi cho mỗi loại Có nguồn gốc. –

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