Ковариантные виртуальные функции возвращают проблему типа - PullRequest
3 голосов
/ 22 февраля 2011

У меня есть следующий код:

#include <iostream>
using namespace std;

class Child1
{
    int i;
};

class Child2 : public Child1
{
    int j;
};

class Base1
{

public:

    virtual Child1& getChildren()
    {
        cout << "Children1" << endl;
        return children;
    }

private:

    Child1 children;
};

class Base2 : public Base1
{

public:

    virtual Child2& getChildren()
    {
        cout << "Children2" << endl;
        return children;
    }

private:

    Child2 children;
};

Этот код компилируется нормально, но когда я меняю тип возврата getChildren() с ссылочного типа на тип объекта в одном или обоих Base1 и Base2 (например, virtual Child2 getChildren(), я получаю следующую ошибку в Visual Studio 2010 :

error C2555: 'Base2::getChildren': overriding virtual function return type differs and is not covariant from 'Base1::getChildren'

Я хочу знать, почему я не получаю эту ошибку при использовании ссылки и получаю ее в противном случае. Это ошибка в VS2010? Поскольку стандарт C ++ (согласно этой странице на веб-сайте Microsoft) говорит что-то вроде: Возвращаемый тип переопределяющей функции должен быть либо идентичным возвращаемому типу переопределенной функции, либо ковариантно с классами. функций. И класс в типе возврата B :: f является тем же классом, что и класс в типе возврата D :: f или, является однозначным прямым или косвенным базовым классом класс в возвращаемом типе D :: f и доступен в D.

P.S. У меня нет доступа к стандарту на данный момент, поэтому я не могу подтвердить приведенную выше цитату.

Ответы [ 3 ]

15 голосов
/ 22 февраля 2011

Вы пропустили другую часть, которую они цитировали: "Если функция D :: f переопределяет функцию B :: f, возвращаемые типы функций ковариантны, если они удовлетворяют следующим критериям: (1) оба являются указатели на классы или ссылки на классы "

4 голосов
/ 22 февраля 2011

Они должны быть ссылками или указателями, а не конкретными классами.Эти требования могут вполне удовлетворительно жить в соответствии с условием «согласовать с» в вашей цитате MS.Во второй части говорится о «классе возвращаемого типа» - обратите внимание на осторожность, с которой они избегали «возвращаемого класса» именно потому, что это компонент класса возвращаемого указателем или ссылочным классом типа.

Подумайте о том, для чего нужна ковариация: вы возвращаете объект, и некоторый существующий код, написанный для базового класса, может захотеть справиться с этим, но через виртуальную диспетчеризацию в конечном итоге вы получите один из ваших объектов.Если бы они могли быть разными по размеру, как могли бы храниться объекты?Этот беспорядок обходится косвенным образом ... вы можете решить, где они (некоторый буфер, общая память, куча), а ковариантный тип возврата - указатель или ссылка на него.

0 голосов
/ 07 января 2015

Если вы меняете строковые преобразования, такие как std :: string, на std :: wstring или любые строковые преобразования виртуальных функций, вам нужно изменить суперкласс той виртуальной функции, где фактически объявлена ​​эта виртуальная функция.Вам нужно менять везде, где вы используете функцию, в которой вы меняете строковые преобразования.

В моем случае это случится, надеюсь, это кому-нибудь поможет ....

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...