2016-07-08 40 views
3

爲什麼呼籲在下面的程序都BDB::operator()爲什麼在模板中調用基類的運算符?

#include <algorithm> 
#include <iostream> 
#include <iterator> 
#include <vector> 

class B { 
public: 
    virtual ~B() {} 
    virtual bool operator()(int a, int b) { return a < b; } 
}; 

class D : public B { 
public: 
    bool operator()(int a, int b) override { return a > b; } 
}; 

void f(B& b, std::vector<int>& v) 
{ 
    std::sort(v.begin(), v.end(), b); 
    std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " ")); 
    std::cout << std::endl; 
} 

int main() 
{ 
    const std::vector<int> v{5, 3, 8, 1, 7}; 

    std::vector<int> vb(v); 
    B b; 
    f(b, vb); 

    std::vector<int> vd(v); 
    D d; 
    f(d, vd); 

    return 0; 
} 

如果我改變std::sort(v.begin(), v.end(), b)這樣:

std::sort(v.begin(), v.end(), 
      [&](int x, int y){ return b.operator()(x, y); }); 

然後向後f(d, vd)種種預期。

我最好的理解是std::sort(v.begin(), v.end(), b)使用&B::operator()而不是b.operator()。我無法找到一個明確的解釋,雖然,它似乎並不完全合乎邏輯的,因爲編譯器應該能夠看到B有虛表。

+3

'的std :: sort'由值取比較器。這裏真正的教訓是,非葉基類應該是抽象的,這將避免正是這種誤解。 –

回答

4

std::sort簽名:

template< class RandomIt, class Compare > 
void sort(RandomIt first, RandomIt last, Compare comp); 

參數comp將由值這裏通過,所以f(d, vd);dslicing copiedB然後B::operator()將被調用。

您可能使f()一個模板函數。

template <typename COMP> 
void f(COMP& b, std::vector<int>& v) 
{ 
    std::sort(v.begin(), v.end(), b); 
    std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " ")); 
    std::cout << std::endl; 
} 

其他建議:這將是更好地使B::operator()D::operator() const成員函數,並改變b參數類型爲const引用。

LIVE

+0

隨着(有點偏離主題,但很有價值)爲'運營商const正確性建議()'成員函數;可能值得添加也讓'f'中的參數'b'是一個const引用。 – dfri

+0

@dfri當然,補充。事實上,我已經在我的現場演示中完成了它。 :) – songyuanyao

+0

啊,我沒有檢查現場演示:) – dfri