Передать подклассы функции, которая принимает их суперкласс

Допустим, у меня есть три класса - Animal, Cat а также Dog, где Cat а также Dog подклассы Animal (это звучит как первые лекции, но я обещаю, что это не домашняя работа, а упрощение реального кода)

Dog* spike = new Dog(); 
Cat* puss = new Cat();   

int main(int argc, char** argv)
{
    function(spike, puss);
    return 0;
}

void function(Animal *pet, Animal *pet2)
{
   magic->andSoForth();
}

Теперь это генерирует следующую ошибку:

Cannot convert parameter 1 from 'Dog *' to 'Animal'
  No constructor could take the source type,
    or constructor overload resolution was ambiguous

Изменение параметров для точного соответствия приводит к аналогичным ошибкам, только из-за того, что они не могут преобразовать класс в один и тот же класс.

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

РЕДАКТИРОВАТЬ

Решение бывает так: указатели смущают всех.

  • Объявите указатели.
  • Отправлять указатели в качестве аргументов функции, которая НЕ обрабатывает указатели.

В моем примере я отправил "not-pointers" в функцию, которая хотела указатели, я просто переключил это. Теперь все отлично работает.

5 ответов

Решение

Вот как это должно выглядеть.

Dog* spike = new Dog();
Cat* puss = new Cat();

function(*spike, *puss);

void function(Animal pet, Animal pet2)
{
   //magic
}

Проверено и работает.

Когда вы динамически выделяете новый объект, вы получаете указатель на этот объект. Так что вам нужно хранить его в указателе так:

Dog* spike = new Dog();
Cat* puss = new Cat();

Затем вы можете пройти spike или же puss для любого параметра типа Animal*предполагая Dog а также Cat действительно наследовать от Animal, Это основы полиморфизма в C++:

Значение типа "указатель на cv" D", где D это тип класса, может быть преобразован в значение типа "указатель на cv" B", где B является базовым классом (пункт 10) D,

Вы могли бы, конечно, сохранить их сразу же, как Animal*:

Animal* spike = new Dog();
Animal* puss = new Cat();

Не забудь delete их. Еще лучше, не используйте new совсем:

Dog spike;
Cat puss;
void function(const Animal&, const Animal&);
function(spike, puss);

Разумно предположить, что проблема заключается в назначении указателя на не указатель, или наоборот. Но ваш код не является реальным кодом, и ваши сообщения об ошибках, по-видимому, не являются реальными сообщениями об ошибках. Так что это все догадки, в частности те уже опубликованные ответы, которые говорят "вот оно" (возможно, но не обязательно, а неопределенность - полностью ваша собственная вина).


РЕДАКТИРОВАТЬ: ОП изменил код вопроса через 10 секунд после того, как я опубликовал это.

Код по-прежнему не совпадает с предполагаемым сообщением об ошибке.

Я не собираюсь преследовать этот вопрос, так как он меняется.


Теперь о том, что делать...


Не использовать new,

Опытные программисты на C++ иногда используют new контролируемыми способами, завернутые в подходящий код. Некомпетентные программисты на C++ часто используют new как само собой разумеющееся. Но в целом вам это не нужно, и это проблематично, поэтому лучше по умолчанию не используйте его.

Тогда ваша программа (которую вы забыли показать) будет выглядеть так:

#include <iostream>

struct Animal {};
struct Dog: Animal {};
struct Cat: Animal {};

void function(Animal const& pet1, Animal const& pet2 )
{
   //magicAndSoForth();
}

int main()
{
    Dog spike; 
    Cat puss;

    function( spike, puss );
}

Ваш прототип для function почти наверняка говорит

void function(Animal pet1, Animal pet2);

или что-то очень похожее на это. (Я знаю, у вас есть прототип, так как function появляется после main, Если бы вы не объявили об этом заранее, C++ пожаловался бы, что не может найти function совсем не то, что он принимает неправильные типы аргументов.)

Проблема в том, что ты настоящий function берет указатели. И с тех пор main появляется до реального functionне видит этого. Он видит только объявление того, который принимает фактический Animals, поэтому он пытается использовать это... но терпит неудачу, потому что указатель Animal не является Animal. (Реальный function отличается от прототипа нормально с C++, из-за возможности перегрузки. Насколько знает компилятор, function(Animal, Animal) существует в другом модуле перевода, и вы просто определяете function(Animal*, Animal*) тоже.)

Посмотрите ваш код для объявления functionи заставь это сказать

void function(Animal *pet1, Animal *pet2);

совпадать с фактической сигнатурой функции.

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

PPS: Лучшей идеей было бы вместо этого брать ссылки, как предложено Альфом. Но для того, чтобы сделать это в любом случае, вы должны сначала исправить несоответствие прототипа (или заставить реальную функцию появляться перед кодом, который ее использует)

Ну, что вам нужно сделать, это

Animal *spike = new Dog();
Animal *puss = new Cat();

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

Другие вопросы по тегам