为什么gtest-matchers.h中的MatcherBase类要定义一个VTable,它的用途是什么?

问题描述 投票:0回答:1

为什么

MatcherBase
中的gtest-matchers.h中的
googletest
类定义了
VTable
,它的目的是什么?我推测它实现了类似于虚函数表的机制,但是为什么不直接使用虚函数呢?

VTable
在以下链接的第316行定义:

https://github.com/google/googletest/blob/1d17ea141d2c11b8917d2c7d029f1c4e2b9769b2/googletest/include/gtest/gtest-matchers.h#L316

我尝试搜索并询问一些LLM,但没有得到好的答案。我想得到C++专家的专业解答。谢谢!

c++ googletest
1个回答
0
投票

VTable
类确实用于实现动态调度,这是常规虚拟表所做的事情。代码本质上是这样的:

template <typename T>
class MatcherBase{
 public:
  bool MatchAndExplain(const T& x, MatchResultListener* listener) const {
    return vtable_->match_and_explain(*this, x, listener);
  }
  template <typename P>
  static auto MatchAndExplainImpl(const MatcherBase& m, const T& value,
                                  MatchResultListener* listener)
      -> decltype(P::Get(m).MatchAndExplain(value, listener->stream())) {
    return P::Get(m).MatchAndExplain(value, listener->stream());
  }
protected:
  template <typename U>
  explicit MatcherBase(const MatcherInterface<U>* impl)
      : vtable_(nullptr), buffer_() {
    Init(impl);
  }
  template <typename M, typename = typename std::remove_reference<
                            M>::type::is_gtest_matcher>
  MatcherBase(M&& m) : vtable_(nullptr), buffer_() {  // NOLINT
    Init(std::forward<M>(m));
  }
private:
  struct VTable {
    bool (*match_and_explain)(const MatcherBase&, const T&,
                              MatchResultListener*);
  };
  template <typename P>
  const VTable* GetVTable() {
    static constexpr VTable kVTable = {&MatchAndExplainImpl<P>};
    return &kVTable;
  }
  template <typename M>
  struct ValuePolicy {
    static const M& Get(const MatcherBase& m) {
      // When inlined along with Init, need to be explicit to avoid violating
      // strict aliasing rules.
      const M* ptr =
          static_cast<const M*>(static_cast<const void*>(&m.buffer_));
      return *ptr;
    }
  };
  // Other ValuePolicy class templates... 
  template <typename M>
  void Init(M&& m) {
    using MM = typename std::decay<M>::type;
    using Policy = ValuePolicy<MM>;
    vtable_ = GetVTable<Policy>();
    Policy::Init(*this, std::forward<M>(m));
  }
  const VTable* vtable_;
  Buffer buffer_;
};

从上面我们可以看到

MatcherBase<T>::MatchAndExplain()
调用了相应的
MatcherBase<T>::MatchAndExplainImpl<P>()
,其中
P
是一个
ValuePolicy
类,其类型由构造函数确定。这称为基于策略的模式。
ValuePolicy
确定如何通过
MatcherBase<T>::buffer_
ValuePolicy::Get()
解释为匹配器,对于上面列出的构造函数,它可以是
MatcherInterface<U>
(请注意,
U
不一定与
T
相同),或其他一些实现了
MatchAndExplain
函数的类。特别是,该类(通常是用户定义的匹配器)不需要继承
MatcherInterface<U>
类,它只需要实现相应的功能。 gmock 文档 中给出的自定义匹配器示例如下所示, 请注意,它不会继承任何东西。

class BarPlusBazEqMatcher {
 public:
  using is_gtest_matcher = void;
  //...

  bool MatchAndExplain(const Foo& foo,
                       std::ostream* /* listener */) const {
    return (foo.bar() + foo.baz()) == expected_sum_;
  }
  //...
 private:
  const int expected_sum_;
};

一般来说,当类具有公共接口(例如实现了特定功能)但不共享公共父类时,您无法使用该语言提供的虚函数系统,而必须推出自己的动态调度机制。请注意,您也无法使

ValuePolicy
模板类继承公共
ValuePolicyBase
,因为
ValuePolicy::Get()
函数不共享公共返回类型。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.