2009-03-04 39 views
27

Lợi ích của việc kế thừa từ std :: binary_function (hoặc std :: unary_function) là gì?Lợi ích của việc kế thừa từ std :: binary_function (hoặc std :: unary function) là gì?

Ví dụ tôi có mã như:

class Person 
{ 
public: 
    Person(); 
    Person(int a, std::string n); 
    Person(const Person& src); 

    int age; 
    std::string name; 
}; 

Person::Person() 
      : age(0) 
      , name("") 
       {}; 

Person::Person(int a, std::string n) 
: age(a) 
, name(n) 
{}; 

Person::Person(const Person& src) 
{ 
    age = src.age; 
    name = src.name; 
}; 

struct PersonPrint : public std::unary_function<Person, void>{ 
    void operator() (Person p){ 
    std::cout << " Person age: " << p.age 
       << " name: " << p.name << std::endl; 
    } 
}; 

struct PersonGreater : public std::binary_function<Person, Person, bool>{ 
    bool operator()(const Person& p1, const Person p2){ 
    if (p1.age > p2.age) return true; 
    if (p1.name.compare(p2.name) > 0) return true; 
    return false; 
    } 
}; 

int main(int count, char** args) 
{ 
    std::vector<Person> personVec; 
    Person p1(10, "Person1"); 
    Person p2(12, "Person2"); 
    Person p3(12, "Person3"); 

    personVec.push_back(p1); 
    personVec.push_back(p2); 
    personVec.push_back(p3); 

    std::cout << "before sort: " << std::endl; 
    std::for_each(personVec.begin(), personVec.end(), PersonPrint()); 
    std::sort(personVec.begin(), personVec.end(), PersonGreater()); 
    std::cout << "after: " << std::endl; 
    std::for_each(personVec.begin(), personVec.end(), PersonPrint()); 
} 

Nhưng tôi cũng có thể viết mã này mà không có hình thức thừa kế std::unary_function/std::binary_function?

struct PersonPrint { 
    void operator() (Person p) { 
     std::cout << " Person age: " << p.age << " name: " << p.name << std::endl; 
    } 
}; 

struct PersonGreater { 
    bool operator()(const Person& p1, const Person p2) { 
     if (p1.age > p2.age) return true; 
     if (p1.name.compare(p2.name) > 0) return true; 
     return false; 
    } 
}; 

CẬP NHẬT

std :: binary_function và std :: unary_function đang bị phản đối như của C++ 11 Xem bình luận bằng @AlexandreC.

+2

Chúng không được dùng nữa trong C++ 11 (tất nhiên, không có C++ 11 tại thời điểm câu hỏi đã được hỏi). –

+0

@AlexandreC. chúng ta nên sử dụng cái gì? trong tiêu chuẩn mã hóa C++, andrei đã đề cập rằng chúng rất quan trọng để xây dựng các functors được sử dụng với các thuật toán stl –

+0

@kirill_igum: Bây giờ 'decltype',' auto' và 'std :: result_of' có sẵn, bạn không cần phải kế thừa bất cứ điều gì. Ngoài ra, 'bind1st' và' bind2nd' đã không còn được dùng để ủng hộ 'bind' nữa. –

Trả lời

29

thừa kế từ [unary | nhị phân] _function chỉ mang đến cho bạn một typedefs bổ sung trong lớp học của bạn:

Đối unary_function

argument_type 
result_type 

Đối binary_function

first_argument_type 
second_argument_type 
result_type 

nào là những loại bạn vượt qua thành [unary | binary] _function. Trong trường hợp của bạn không có lợi ích.

Nếu bạn định sử dụng các hàm Functors của bạn với các trình sửa đổi khác của Functors như not1, bind1st bạn phải kế thừa từ [unart | binart] _function.

Và nếu bạn định lưu trữ thông tin mẫu này cho mục đích của mình thì tốt hơn là nên sử dụng giải pháp đã sẵn sàng.

+1

Bạn nên lưu ý rằng các typedef này được sử dụng bởi thư viện chức năng stl, ví dụ các negators not1 và not2. –

+0

@Luc: Cảm ơn bạn đã thông báo. –

9

Giống như Mykola giải thích, họ chỉ cần thêm typedef. Hãy tưởng tượng cho PersonGreater của bạn, bạn muốn sửa đối số đầu tiên cho một số người. Các binder1st sẽ cần phải lưu trữ các đối số đầu tiên một nơi nào đó, và do đó, nó cần loại đối số đầu tiên. binary_function quy định rằng khi một typedef:

// get a function object that compares person1 against 
// another person 
std::bind1st(PersonGreater(), person1) 

Bây giờ, quay trở lại binder1st đối tượng đều biết rằng các loại của các đối số cần thiết để lưu trữ là loại người.

Một số đối tượng chức năng phủ nhận kết quả của một đối tượng hàm khác. Ở đây chúng ta cần loại lập luận quá:

template <class Predicate> 
class unary_negate 
    : public unary_function<typename Predicate::argument_type,bool> { 
    Predicate pred; 
public: 
    explicit unary_negate(const Predicate& pred):pred(pred) { } 
    bool operator()(const typename Predicate::argument_type& x) const { 
     return !pred(x); 
    } 
}; 

Đó cũng có thể sử dụng một templated operator(), nhưng tiêu chuẩn định nghĩa nó để sử dụng các loại argument_type như tham số. Bản thân negator có nguồn gốc từ unary_function và cần phải cung cấp kiểu đối số đầu tiên.

Đôi khi, mọi người cố gắng sử dụng [unary,binary]_function để lưu trữ đối tượng/con trỏ hàm. Tuy nhiên, chúng không thể được sử dụng cho điều đó. boost::function hoàn thành công việc đó và sẽ được áp dụng trong Tiêu chuẩn tiếp theo là std::function.

+0

@litb: Điểm tốt về bind1st. Không bao giờ sử dụng đối tượng functors của tôi với bind1st. –

16

Bên cạnh kiểu chữ (đã được đề cập), cũng có thể là khía cạnh dễ đọc. Khi tôi thấy struct Foo {... suy nghĩ đầu tiên của tôi sẽ là "Foo là một loại". Nhưng với struct Foo : public unary_function<... Tôi đã biết rằng Foo là một functor. Đối với một lập trình viên (không giống như các trình biên dịch), các kiểu và các hàm functors khá khác biệt.

+6

Để nghiêm khắc, Foo không bao giờ là một thư viện. Nó là một kiểu, hoặc, đặc biệt, một functor * type *. Functors mình là instantiations của các loại functor. –

3

Đó là một dạng tài liệu mạnh mẽ được thực thi bởi trình biên dịch.

Bằng cách kế thừa, bạn đang thực hiện lời hứa rằng bạn sẽ triển khai giao diện binary_function và trình biên dịch sẽ giữ bạn. Sau đó, khách hàng có thể tin tưởng rằng lớp của bạn có thể được sử dụng bất cứ nơi nào một binary_function là cần thiết.

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