2009-06-24 37 views
7

Tôi muốn xây dựng một lớp cơ sở (trừu tượng) (gọi là type::base) với một số tính phổ biến và giao diện thông thạo, vấn đề tôi đang đối mặt là kiểu trả về của tất cả các phương thức đóGiao diện thông thạo và kế thừa trong C++

class base { 
    public: 
     base(); 
     virtual ~base(); 

     base& with_foo(); 
     base& with_bar(); 
    protected: 
     // whatever... 
    }; 

Bây giờ tôi có thể làm cho phân nhóm, ví dụ:

class my_type : public base { 
    public: 
     myType();   
     // more methods... 
    }; 

vấn đề này được đưa ra khi sử dụng những phân nhóm như thế này:

my_type build_my_type() 
{ 
    return my_type().with_foo().with_bar(); 
} 

Điều này sẽ không biên dịch vì chúng tôi đang trả lại cơ sở thay vì my_type.

Tôi biết rằng tôi có thể chỉ:

my_type build_my_type() 
{ 
    my_type ret; 
    ret.with_foo().with_bar(); 

    return ret; 
} 

Nhưng tôi đã suy nghĩ làm thế nào tôi có thể thực hiện nó, và tôi đã không tìm thấy bất kỳ ý tưởng hợp lệ, một số gợi ý?

+0

Tôi đã xóa nội dung không gian tên vì nó không có gì (theo như tôi có thể thấy) để làm với câu hỏi –

Trả lời

4

Vấn đề này "mất loại" có thể được giải quyết bằng các mẫu - nhưng nó khá phức tạp.

Ví dụ:

class Pizza 
{ 
    string topping; 
public: 
    virtual double price() const; 
}; 

template <class T, class Base> 
class FluentPizza : public Base 
{ 
    T* withAnchovies() { ... some implementation ... }; 
}; 

class RectPizza : public FluentPizza<RectPizza, Pizza> 
{ 
    double price() const { return length*width; :) } 
}; 

class SquarePizza : public FluentPizza<SquarePizza, RectPizza> 
{ 
    ... something else ... 
}; 

Bạn có thể sau đó viết

SquarePizza* p=(new SquarePizza)->withAnchovies(); 

Các mô hình là thay vì

class T : public B 

bạn viết

class T : public Fluent<T, B> 

cách tiếp cận khác có thể không sử dụng giao diện thông thạo trên Các vật thể, nhưng trên con trỏ thay vì:

class Pizza { ... }; 
class RectPizza { ... }; 
class SquarePizza { ... whatever you might imagine ... }; 

template <class T> 
class FluentPizzaPtr 
{ 
    T* pizza; 
public: 
    FluentPizzaPtr withAnchovies() { 
    pizza->addAnchovies(); // a nonfluent method 
    return *this; 
    } 
}; 

Sử dụng như thế này:

FluentPizzaPtr<SquarePizza> squarePizzaFactory() { ... } 

FluentPizzaPtr<SquarePizza> myPizza=squarePizzaFactory().withAnchovies(); 
+0

Bạn có thể cung cấp một ví dụ không? Chắc hẳn sẽ hấp dẫn. – liori

+0

cf. bản chỉnh sửa. Nó có thể là thú vị, tôi không biết nếu tôi cá nhân sử dụng nó, mặc dù ... – jpalecek

+0

Vì vậy, bạn thực sự chuyển sang con trỏ. Sau đó, bạn chỉ có thể sử dụng đa hình đơn giản, không có CRTP và trả lại cơ sở *. – liori

-2

Con đường tôi muốn làm điều đó trong C#, và tôi tin rằng nó sẽ làm việc trong C++ cũng là để cung cấp một cài đặt mặc định cho with_foo()with_bar() ... Hãy tha thứ cho tôi C#, nhưng:

class base { 
    virtual base with_foo() 
    { throw new NotImplementedException(); } 
    virtual base with_bar(); 
    { throw new NotImplementedException(); } 
} 
+0

Nhưng điều này không khắc phục được sự cố - sự cố là loại không phù hợp, không liên quan đến câu hỏi . – jpalecek

-1

Trong C++ bạn nên khôi phục con trỏ hoặc tham chiếu thay vì giá trị. Ngoài ra, bạn có thể muốn giải thích ý bạn là "giao diện thông thạo".

+2

http://en.wikipedia.org/wiki/Fluent_interface – liori

+1

Xin lỗi - ngay sau khi tôi thấy tên "Martin", máy dò bullsh * t của tôi tắt hết âm lượng và tôi không thể đọc được nữa. Dường như không quan trọng nếu đó là tên họ hoặc họ. –

+0

Có gì sai với Martin Fowler? – Tobias

0

Một giải pháp sẽ làm việc như thế này:

return *static_cast<my_type*>(&my_type().with_foo().with_bar()); 

Sử dụng static_cast cơ bản cho trình biên dịch 'Tôi biết những gì tôi đang làm gì ở đây'.

5

Bạn nên trở về tài liệu tham khảo/con trỏ, và bạn không nên cần phải giữ cho loại thông tin.

class base { 
    public: 
    base(); 
    virtual ~base(); 

    base &with_foo(); 
    base &with_bar(); 
    protected: 
    // whatever... 
}; 

class my_type : public base { 
    public: 
    my_type();   
    // more methods... 
}; 

base *build_my_type() 
{ 
    return &new my_type()->with_foo().with_bar(); 
} 

Bạn đã có trình phá hủy ảo. Có lẽ bạn có các chức năng ảo khác.Truy cập mọi thứ thông qua kiểu cơ sở và các hàm ảo được khai báo ở đó.

+0

Vấn đề là tôi không muốn mất loại. – blaxter

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