Передать подклассы функции, которая принимает их суперкласс
Допустим, у меня есть три класса - 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
не видит этого. Он видит только объявление того, который принимает фактический Animal
s, поэтому он пытается использовать это... но терпит неудачу, потому что указатель 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();
По сути, все ваши определения указателей должны быть базового класса, и они могут быть инициализированы с помощью указателей производного класса.