Виртуальной функции C++ тип возвращаемого значения


возможно ли для унаследованного класса реализовать виртуальную функцию с другим типом возврата (не используя шаблон в качестве возврата)?

3 65

3 ответа:

в некоторых случаях, да, это законно для производного класса, чтобы переопределить виртуальную функцию, используя другой тип возвращаемого значения, пока тип возвращаемого значения ковариантные С исходным типом возврата. Например, рассмотрим следующее:

class Base {
public:
    virtual ~Base() {}

    virtual Base* clone() const = 0;
};

class Derived: public Base {
public:
    virtual Derived* clone() const {
        return new Derived(*this);
    }
};

здесь Base определяет чисто виртуальную функцию с именем clone что возвращает Base *. В производной реализации эта виртуальная функция переопределяется с помощью возвращаемого типа Derived *. Хотя тип возвращаемого значения не то же самое, что в базе, это совершенно безопасно, потому что в любое время вы будете писать

Base* ptr = /* ... */
Base* clone = ptr->clone();

вызов clone() всегда будет возвращать указатель на Base объект, так как даже если он возвращает Derived*, этот указатель неявно преобразуется в Base* и операция четко определена.

как правило, возвращаемый тип функции никогда не считается частью ее сигнатуры. Можно переопределить функцию-член с любым типом возвращаемого значения, если тип возвращаемого значения является ковариантным.

да. Возвращаемые типы могут быть разными, если они ковариантные. Стандарт C++ описывает его следующим образом (§10.3/5):

тип возврата переопределяющей функции должен быть либо идентичен типу возврата переопределенной функции, либо ковариантные С классами функций. Если функция D::f переопределяет функцию B::f, возвращаемый тип функций ковариантен, если удовлетворяют следующим критериям:

  • оба являются указателями на классы или ссылки на классы98)
  • класс в возвращаемом типе B::f это тот же класс, что и класс в возвращаемом типе D::f или, является однозначным прямым или косвенным базовым классом класса в возвращаемом типе D::f и работает в D
  • оба указателя или ссылки имеют одинаковую cv-квалификацию и тип класса в возвращаемый тип D::f имеет ту же CV-квалификацию, что и CV-квалификация, или меньше, чем тип класса в возвращаемом типе B::f.

сноска 98 указывает, что " многоуровневые указатели на классы или ссылки на многоуровневые указатели на классы не допускаются."

короче, если D является подтипом B, то возвращаемый тип функции в D должен быть подтип возвращаемого типа функции в B. Этот наиболее распространенный пример - это когда возвращаемые типы сами основаны на D и B, но они не должны быть. Рассмотрим это, где мы две отдельные иерархии типов:

struct Base { /* ... */ };
struct Derived: public Base { /* ... */ };

struct B {
  virtual Base* func() { return new Base; }
  virtual ~B() { }
};
struct D: public B {
  Derived* func() { return new Derived; }
};

int main() {
  B* b = new D;
  Base* base = b->func();
  delete base;
  delete b;
}

причина, по которой это работает, заключается в том, что любой вызывающий func ждет Base указатель. Любой Base указатель будет делать. Так что, если D::func обещает всегда возвращать a Derived указатель, то он всегда будет удовлетворять контракту, выложенному классом предка, потому что любой Derived указатель может быть неявно преобразуется в Base указатель. Таким образом, абоненты всегда будут получать то, что они ожидают.


в дополнение к разрешению типа возврата варьироваться, некоторые языки позволяют типы параметров основной функцией отличаться. Когда они это делают, они обычно должны быть контравариантным. То есть, если B::f принимает a Derived*, потом D::f будет разрешено принять Base*. Потомкам разрешено быть слабее в том, что они примут, и жесткие в чем они возвращаются. C++ не допускает контравариантность типа параметра. Если вы измените типы параметров, C++ считает его совершенно новой функцией, поэтому вы начинаете перегружаться и скрываться. Дополнительные сведения по этой теме см. В разделе ковариантность и контравариантность (информатика) в Википедии.

реализация производного класса виртуальной функции может иметь Ковариантный Тип Возврата.