Тип возвращаемого значения переопределенного класса C ++ - PullRequest
0 голосов
/ 13 декабря 2018

Я думаю, что мой пример ниже объяснит, что я пытаюсь сделать.Я знаю, что не могу переопределить тип возвращаемого значения функции 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;
}

РЕДАКТИРОВАТЬ: Решено

Спасибо всем запредложения.Я нашел способ достичь своей конечной цели.В конце я хотел таблицу полиморфных символов.Я использовал некоторые твои идеи, чтобы заставить это работать.Самым большим прорывом было сделать эту «двустороннюю» функцию плюс.Чтобы добавить две переменные, первая просит другую добавить другую со значением первой:

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

Ответы [ 2 ]

0 голосов
/ 13 декабря 2018

Простой ответ: Вы не можете .Переопределения в C ++ должны возвращать тот же тип, что и исходная функция.

Однако более сложный ответ - , который вы можете сделать, с некоторыми приемами .Одним из приемов было бы использование возвращаемого значения со стертым типом, например, через std::any - подробнее об его использовании на https://en.cppreference.com/w/cpp/utility/any

При std::any функции могут возвращать любое значение, которое они хотят,но оно будет стерто по типу - поэтому вызывающие абоненты должны будут знать, что делать с этим возвращаемым значением ... Что, в некотором смысле, серьезно ограничивает область применения этого решения.Однако и для этого есть место.

0 голосов
/ 13 декабря 2018

Вы не можете.

Статический тип выражения не может зависеть от динамического типа объекта.Например,

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

Какого типа f?

Вы можете решить проблему с помощью std::variant, но это будет означать базовый классзнает, что все типы детей класс может вернуть.Это действительно проблема дизайна, и вы должны ее исправить.

...