【问题标题】:Implement Interface with Anonymous Class in C++在 C++ 中使用匿名类实现接口
【发布时间】:2015-04-25 22:30:08
【问题描述】:

在 java 中,我们可以像这样使用匿名类实现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::string, class &lt;unnamed&gt;)

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

谢谢!

【问题讨论】:

标签: java c++ interface anonymous-class


【解决方案1】:

这里有什么问题?

要使多态性起作用,您需要通过引用(或指针,如果您愿意)传递基类:

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 之前,您可以对函数对象做同样的事情。它稍微冗长一些,但仍然提供比继承方法更短、更高效的代码。)

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • 这也是真的,我没看到:)
    【解决方案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;
    }
    

    【讨论】:

      【解决方案4】:

      为了使这个(多态性)起作用,您必须通过指针或引用 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;
      }
      

      我通常更喜欢使用指针,因为在使用引用时我倾向于忽略多态的可能性。另一方面,它有一个缺点,你必须检查 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;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-16
        相关资源
        最近更新 更多