Ковариантный тип возвращаемого значения и преобразование типа

s->duplicate() возвращает объект типа Box*, но я получаю сообщение об ошибке при инициализации с Box*, Похоже, он превращается обратно в Shape*, Какой смысл иметь ковариантные возвращаемые типы, если он конвертируется обратно в указатель базового класса ?:

struct Shape
{
virtual Shape* duplicate()
{
return new Shape;
}
};

struct Box : Shape
{
virtual Box* duplicate()
{
return new Box;
}
};

int main()
{
Shape* s = new Box;
Box*   b = s->duplicate();
}

Ошибка:

main.cpp:22:12: error: cannot initialize a variable of type 'Box *' with an rvalue of type 'Shape *'
Box*   b = s->duplicate();
^   ~~~~~~~~~~~~~~
1 error generated.

8

Решение

Хотя Box::duplicate является вызывается во время выполнения (через виртуальную диспетчеризацию), и хотя Box::duplicate делает переопределение Shape::duplicate (ковариантно), и хотя Box::duplicate делает вернуть Box*, вы все равно получите Shape* указатель, потому что вы звоните duplicate() через Shape* указатель и Shape* тип возвращаемого значения Shape::duplicate()и компилятор видит только то, что вы звоните Shape::duplicateне Box::duplicate,

C ++ не может динамически выбирать типы, поэтому это лучшее, что он может сделать. Ваш Box* автоматически преобразуется в Shape* на выходе из Box::duplicate, Как сказал Барри, «он все еще должен компилироваться во время компиляции, и во время компиляции все, что мы знаем, это то, что он возвращает Shape*».

Затем, чтобы превратить его в Box* опять же, вам нужно явно привести его (используя static_cast или же dynamic_cast) потому что неявного преобразования не существует.

[C++11: 10.3/7]: Тип возврата переопределяющей функции должен быть либо совпадает с типом возврата переопределенной функции, либо ковариантный с классами функций. [..]

[C++11: 10.3/8]: Если тип возврата D::f отличается от типа возврата B::fтип класса в возвращаемом типе D::f должен
быть полным в момент объявления D::f или должен быть типом класса D, Когда переопределяющая функция вызывается как последняя переопределенная переопределенная функция, ее результат преобразуется в тип, возвращаемый (статически выбранной) переопределенной функцией. (5.2.2). [..]

В стандартном тексте приведен соответствующий пример.

9

Другие решения

Дело не в том, чтобы сделать это:

Box*   b = s->duplicate();

Это, очевидно, не может работать, так как Shape::duplicate() возвращает Shape*, Дело скорее в том, чтобы принять Box* если ты звонишь duplicate() на Box непосредственно:

Box* old = new Box;
Box* b = old->duplicate(); // OK! We know it's a Box
5

По вопросам рекламы [email protected]