在C ++中使用匿名类实现接口

时间:2015-02-24 10:35:06

标签: java c++ interface anonymous-class

在java中,我们可以使用Anonymous类实现interface,如下所示:

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>

这里有什么问题?还有其他办法吗?

谢谢!

4 个答案:

答案 0 :(得分: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之前,您可以使用函数对象执行相同的操作。它稍微冗长一点,但仍然提供比继承方法更短,更高效的代码。)

答案 1 :(得分:3)

C ++仅支持引用和指针类型的多态。将您的方法更改为

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

然后你也可以将Predicate的子类传递给这个函数。

答案 2 :(得分: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 :(得分:3)

为了使(多态)工作,你必须通过指针或引用传递谓词:

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;
}

我通常更喜欢使用指针,因为在使用引用时,我倾向于忽略多态性的可能性。另一方面,它有一个缺点,你必须检查nullptr并且语法不像以前那么好。

实现这一点的更常见的方法是使用lambdas例如:

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;
}