2015-02-24 54 views
6

在Java中,我們可以實現匿名類的interface這樣實現接口:與++匿名類用C

import java.util.function.Predicate; 

public class Test { 

    public static void main(String[] args) { 
     System.out.println(testIf("", new Predicate<String>() { 
      @Override 
      public boolean test(String s) { 
       return s.isEmpty(); 
      } 
     })); 
    } 

    public static <T> boolean testIf(T t, Predicate<T> predicate) { 
     return predicate.test(t); 
    } 

} 

自從Java 8:

System.out.println(testIf("", String::isEmpty)); 

我們如何能做到這一點在C++? 我寫了下面的代碼,但我得到編譯錯誤:

#include "stdafx.h" 
#include <iostream> 
#include <string> 
using namespace std; 

template <class T> 
class Predicate 
{ 
public: 
    virtual bool test(T) = 0; 
}; 

template <class T> 
bool testIf(T t, Predicate<T> predicate) 
{ 
    return predicate.test(t); 
} 

int main() 
{ 
    class : public Predicate <string> { 
    public: 
     virtual bool test(string s) 
     { 
      return s.length() == 0; 
     } 
    } p; 
    string s = ""; 
    cout << testIf(s, p); 
    cin.get(); 
    return 0; 
} 

錯誤:沒有的功能模板「testIf」實例相匹配的參數列表 參數類型有:(std::stringclass <unnamed>

這裏有什麼問題?還有其他方法可以做到嗎?

謝謝!

+2

你可以看看http://stackoverflow.com/questions/991062/passing-unnamed-classes-through-functions – Prashant 2015-02-24 10:41:01

回答

9

有什麼不對嗎?

對於多態性的工作,你需要按引用傳遞基類(或指針,如果你喜歡):

bool testIf(T t, Predicate<T> & predicate) 
          ^

隨着該固定,代碼工作對我來說,雖然它的氣味,而我的口味太多的Java。

還有其他方法可以做到嗎?

在C++ 11或更高版本中,無論是在性能還是代碼的噪聲方面,lambda都會更高效。它不需要定義和繼承基類,並調用虛函數。

template <class T, class Predicate> 
bool testIf(T t, Predicate predicate) 
{ 
    return predicate(t); 
} 

testIf(s, [](string const & s){return s.length() == 0;}); 

(C++ 11之前,你可以做同樣的事情用一個函數對象,這是稍微詳細,但還是給了短,比繼承方法更高效的代碼。)

3

C++僅支持引用和指針類型的多態性。將您的方法更改爲

template <class T> 
bool testIf(T t, Predicate<T> & predicate) 
{ 
    return predicate.test(t); 
} 

然後您還可以將Predicate的子類傳遞給此函數。

+0

這是真的太多,我沒看出來:) – amchacon 2015-02-24 10:46:44

3

你可以用一個指針函數:

#include "stdafx.h" 
#include <iostream> 
#include <string> 
using namespace std; 

template <class T> 
class Predicate 
{ 

public: 
    bool (*test)(T); 
}; 

template <class T> 
bool testIf(T t, Predicate<T> predicate) 
{ 
    return predicate.test(t); 
} 

bool one_test(string e) 
{ 
    return e.length() == 0; 
} 

int main() 
{ 
    Predicate<string> p; 
    p.test = one_test; 
    string s = ""; 
    cout << testIf(s, p); 
    cin.get(); 
    return 0; 
} 
3

在爲了使這一(多態性)工作,您必須通過指針或引用傳遞謂詞testIF:

template <class T> 
bool testIf(T t, Predicate<T>* predicate) 
{ 
    if (predicate == nullptr) return true; 
    return predicate->test(t); 
} 

int main() 
{ 
    class : public Predicate <string> { 
    public: 
     virtual bool test(string s) 
     { 
      return s.length() == 0; 
     } 
    } p; 
    string s = ""; 
    cout << testIf(s, &p); 
    cin.get(); 
    return 0; 
} 

我通常喜歡使用指針,因爲我往往忽略多態性的posibility,當引用用過的。另一方面,它有缺點,你必須檢查nullptr,並且語法不像以前那麼好。

更常見的實現方法是使用lambda表達式。:

template <class T,class Pred> 
bool testIf2(T t, Pred predicate) 
{ 
    return predicate(t); 
} 

int main() 
{ 
    auto pred = [](const string& s){return s.length() == 0; }; 
    string s = ""; 
    cout << testIf2(s, pred); 
    cin.get(); 
    return 0; 
}