为什么动态调度在模板函数中不起作用?

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

我有以下代码。有一个基类 (

Node
) 和一个派生类 (
NumberExprNode
),每个类都有一个虚拟相等方法。

#include <vector>
#include <memory>
#include <iostream>

template<typename T>
bool operator==(const std::vector<std::unique_ptr<T>>& n1, const std::vector<std::unique_ptr<T>>& n2) {
  std::cout << "Called std::vector equality check" << std::endl;
  if (n1.size() != n2.size()) {
     return false;
   }
   for (size_t i = 0; i < n1.size(); i++) {
    if (!(*n1[i] == *n2[i])) {
      return false;
    }
  }
return true;
}

class Node {
public:
  virtual bool operator==(const Node& other) const {
    std::cout << "Called Node equality check" << std::endl;
    return false;
  }
};

class NumberExprNode : public Node {
  double Val;

public:
  virtual bool operator==(const NumberExprNode& other) const __attribute__((used)) {
    std::cout << "Called NumberExprNode equality check" << std::endl;
    return (Val == other.Val);
  }

  NumberExprNode(double val) : Val(val) {}
};

int main() {
  std::vector<std::unique_ptr<Node>> n_vec1; // Base class Node used here
  n_vec1.emplace_back(std::make_unique<NumberExprNode>(5));
  n_vec1.emplace_back(std::make_unique<NumberExprNode>(6));
  std::vector<std::unique_ptr<Node>> n_vec2;  // Base class Node used here
  n_vec2.emplace_back(std::make_unique<NumberExprNode>(5));
  n_vec2.emplace_back(std::make_unique<NumberExprNode>(6));
  return (n_vec1 == n_vec2);
}

我看到以下内容打印到标准输出:

Called std::vector equality check
Called Node equality check

但是如果我将“main”替换为:

int main() {
  std::vector<std::unique_ptr<NumberExprNode>> n_vec1; // Derived class used here
  n_vec1.emplace_back(std::make_unique<NumberExprNode>(5));
  n_vec1.emplace_back(std::make_unique<NumberExprNode>(6));
  std::vector<std::unique_ptr<NumberExprNode>> n_vec2; // Derived class used here
  n_vec2.emplace_back(std::make_unique<NumberExprNode>(5));
  n_vec2.emplace_back(std::make_unique<NumberExprNode>(6));
  return (n_vec1 == n_vec2);

然后我明白了

Called std::vector equality check
Called NumberExprNode equality check
Called NumberExprNode equality check

打印到标准输出,这就是我想要的。

我觉得这违反直觉。 n_vec1 的每个条目都指向使用派生类初始化的对象。我认为派生类实例具有完整的 vtable。我在 GDB 中单步执行并打印了

*n1[i]
*n2[i]
。我观察到他们每个人都有一个
NumberExprNode
的 vtable。所以我得出的结论是,即使是第一个示例也应该正确分派到被覆盖的
NumberExprNode
。但事实并非如此。这是为什么?
纵观全局,对于我的应用程序,我希望能够采用异构的 

operator==

,其中每个条目都可以指向不同的派生类。我希望相等运算符正确分派到与用于初始化对象的类相对应的正确

std::vector<std::unique_ptr<Node>>
方法。我如何修改/重组我的代码来实现这一目标?
    

c++ templates polymorphism vtable dynamic-dispatch
1个回答
0
投票

operator==

所以 
class NumberExprNode : public Node { double Val; public: virtual bool operator==(const Node& other_) const override { std::cout << "Called NumberExprNode equality check" << std::endl; const auto& other=dynamic_cast<const NumberExprNode&>(other_); return (Val == other.Val); } NumberExprNode(double val) : Val(val) {} };

实际上会覆盖其他

operator==
:
operator==

但是,如果您将 
stieber@gatekeeper:~ $ g++ Test.cpp; ./a.out Called std::vector equality check Called NumberExprNode equality check Called NumberExprNode equality check

与仅

NumberExprNode
进行比较,上面的代码将会抛出异常,因为转换将会失败。
所以,你可以尝试这样的事情:

Node

这将允许测试适用于所有组合 - 然而,我在这里担心的是,我不记得在任何地方实际这样做过,因为它基本上是尝试实现不同类的比较。

© www.soinside.com 2019 - 2024. All rights reserved.