C ++派生类覆盖返回类型

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C ++派生类覆盖返回类型相关的知识,希望对你有一定的参考价值。

我想我下面的例子将解释我想要做的事情。我知道我不能覆盖eval()函数的返回类型,除非它们是协变量,所以显然我做错了。我的问题:我如何拥有一个多态基类和派生类,可以用不同的方式评估自己?

#include <iostream>

class Node {
public:
  virtual void eval() = 0;
};

class IntNode: public Node {
public:
  IntNode() { val = 0; }
  IntNode(int i) { val = i; }
  int eval() { return val; }
private:
  int val;
};

class FloatNode: public Node {
public:
  FloatNode() { val = 0; }
  FloatNode(float i) { val = i; }
  float eval() { return val; }
private:
  float val;
};

int main() {
  Node *a = new IntNode(5);
  Node *b = new FloatNode(2.3);
  std::cout << a->eval() << std::endl;
  std::cout << b->eval() << std::endl;
  return 0;
}

编辑:已解决

谢谢大家的建议。我找到了实现自己最终目标的方法。最后我想要一个多态符号表。我用了一些你的想法来实现这一点。最大的突破是做到了“双面”加功能。要添加两个Vars,第一个要求另一个使用第一个值添加另一个Vars:

#include <iostream>
#include <unordered_map>
#include <string>

using namespace std;

class Var {
public:
  virtual void print() = 0;
  virtual Var *plus(int i) = 0;
  virtual Var *plus(float f) = 0;
  virtual Var *plus(Var *other) = 0;
};

class IntVar: public Var {
public:
  // constructors
  IntVar();
  IntVar(int i);
  void print();
  // operations
  Var *plus(int i);
  Var *plus(float f);
  Var *plus(Var *other);
private:
  int val;
};

class FloatVar: public Var {
public:
  // constructors
  FloatVar();
  FloatVar(float f);
  void print();
  // operations
  Var *plus(int i);
  Var *plus(float f);
  Var *plus(Var *other);
private:
  float val;
};

// constructors
IntVar::IntVar() { val = 0; }
IntVar::IntVar(int i) { val = i; }
void IntVar::print() { cout << "" << val << endl; }
// operations
Var *IntVar::plus(int i) { return new IntVar(i+val); }
Var *IntVar::plus(float f) { return new FloatVar(f+val); }
Var *IntVar::plus(Var *other) { return other->plus(val); }

// constructors
FloatVar::FloatVar() { val = 0; }
FloatVar::FloatVar(float f) { val = f; }
void FloatVar::print() { cout << "" << val << endl; }
// operations
Var *FloatVar::plus(int i) { return new FloatVar(i+val); }
Var *FloatVar::plus(float f) { return new FloatVar(f+val); }
Var *FloatVar::plus(Var *other) { return other->plus(val); }

int main() {
  unordered_map<string, Var *> symbol_table;
  symbol_table["a"] = new IntVar(5);
  symbol_table["b"] = new FloatVar(2.3);
  symbol_table["c"] = symbol_table["a"]->plus(symbol_table["b"]);

  symbol_table["a"]->print();
  symbol_table["b"]->print();
  symbol_table["c"]->print();
  return 0;
}
答案

你不能。

表达式的静态类型不能取决于对象的动态类型。举个例子:

auto f(Node& n) { return n.eval(); }

什么是f

您可以使用std::variant解决您的问题,但这意味着基类知道子类可以返回的所有类型。这确实是一个设计问题,你应该修复它。

另一答案

一个简单的答案是你不能。 C ++中的覆盖必须返回与原始函数相同的类型。

但是,你可以通过一些技巧获得更复杂的答案。其中一个技巧是使用类型擦除的返回值,例如,通过std::any - 更多关于它在https://en.cppreference.com/w/cpp/utility/any上的用法

使用std::any,函数可以返回他们想要的任何值,但它将被类型擦除 - 因此调用者必须知道如何处理此返回值...在某种意义上,这严重限制了此解决方案的适用范围。但是,也有这个地方。

以上是关于C ++派生类覆盖返回类型的主要内容,如果未能解决你的问题,请参考以下文章

C#中具有相同名称和签名但返回类型不同的方法

比较Java方法的重载与覆盖

C++重载隐藏和覆盖的区别

派生类返回值的 PhpStorm 类型提示

在基类上自动推断派生类上函数的返回类型

覆盖虚函数协变返回类型(两个指针)