Pass subclasses to a function that takes their superclass
Solution 1
This is how it should look.
Dog* spike = new Dog();
Cat* puss = new Cat();
function(*spike, *puss);
void function(Animal pet, Animal pet2)
{
//magic
}
Tested and working.
Solution 2
When you dynamically allocate a new object, you get a pointer to that object. So you need to store it in a pointer like so:
Dog* spike = new Dog();
Cat* puss = new Cat();
You can then pass spike
or puss
for any parameter of type Animal*
, assuming Dog
and Cat
do indeed inherit from Animal
. This is the basics of polymorphism in C++:
A prvalue of type “pointer to cv
D
”, whereD
is a class type, can be converted to a prvalue of type “pointer to cvB
”, whereB
is a base class (Clause 10) ofD
.
You could, of course, have stored them right away as Animal*
:
Animal* spike = new Dog();
Animal* puss = new Cat();
Don't forget to delete
them. Better yet, don't use new
at all:
Dog spike;
Cat puss;
void function(const Animal&, const Animal&);
function(spike, puss);
Solution 3
It's reasonable to assume that the problem you have is assigning a pointer to a non-pointer, or vice versa. But your code is not the real code, and your error messages are apparently not the real error messages. So it's all guesswork, in particular those already-posted answers that say "this is it" (it probably is, but not necessarily, and the uncertainty is entirely your own fault).
EDIT: the OP changed the question's code 10 seconds after I posted this.
The code still does not square with the purported error message.
I'm not going to chase this question as it changes.
Now, as to what to do…
Don't use new
.
Experienced C++ programmers sometimes use new
in controlled ways, wrapped in suitable code. Incompetent C++ programmers often use new
as a matter of course. But in general, you don't need it, and it's problematic, so better as default don't use it.
Then, your program (which you neglected to show) would look like this:
#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 );
}
Solution 4
Your prototype for function
almost certainly says
void function(Animal pet1, Animal pet2);
or something very similar to that. (I know you have a prototype, since function
appears after main
. If you hadn't forward-declared it, C++ would complain that it couldn't find function
at all, not that it's taking the wrong types of args.)
Problem is, your real function
takes pointers. And since main
appears before the real function
, it doesn't see that. It only sees a declaration of one that takes actual Animal
s, so it tries to use that...but fails, because an Animal pointer is not an Animal. (The real function
differing from the prototype is fine with C++, due to the possibility of overloading. As far as the compiler knows, function(Animal, Animal)
exists in another translation unit, and you're just defining function(Animal*, Animal*)
too.)
Look through your code for the declaration of function
, and make it say
void function(Animal *pet1, Animal *pet2);
to match up with the actual function's signature.
PS: this would have been so much easier to figure out if you had included all the relevant declarations.
PPS: A better idea would be to take references instead, as suggested by Alf. But in order to do that anyway, you'd have to fix the prototype mismatch (or make the real function appear before code that uses it) first
XistenZ
Updated on June 04, 2022Comments
-
XistenZ about 2 years
Let's say I have three classes -
Animal
,Cat
andDog
, whereCat
andDog
are subclasses ofAnimal
(this does sound like the first lectures, but it's not homework I promise, just simplifying the real code)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(); }
Now this generates the following error:
Cannot convert parameter 1 from 'Dog *' to 'Animal' No constructor could take the source type, or constructor overload resolution was ambiguous
Changing the parameters to exactly match generates similar errors, only that it says it can't convert from a class to the same class.
I have successfully called the subclasses functions and members that they inherit from the superclass, so I know that this, logically, should work. I just don't know in what twisted way this language want me to bend logic.
EDIT
Solution happen to be: pointers confuse everyone.
- Declare pointers.
- Send pointers as arguments to a function that does NOT handle pointers.
In my example, I sent the "not-pointers" to the function that wanted pointers, I just switched that. Now it works fine.
-
Xymostech over 11 yearsDo you mean
Animal *spike
? -
Nicomoto over 11 yearsSorry, it is Animal * Spike, my mistake, Ive edited it in now..Thanks @Xymostech
-
XistenZ over 11 yearsI do actually declare them as pointers in the real code, sorry I was sloppy doing the mock-up :) I tried to change them to Animal as suggested, but it made no difference. Still the same error :/
-
Joseph Mansfield over 11 years@XistenZ Append to your question the actual code and the line that the error says it corresponds to.
-
XistenZ over 11 yearsI neglected to show my program since I'm just after the principle. I do send parameters when creating the different classes, can you do that with structs? Don't know much about them yet, except they're confusingly alot like classes, but uglier.
-
sehe over 11 years@XistenZ But uglier? I'm all ears (Hint: "C++" != "C#", not even
string.Equals("C++", "C#", StringComparison.UniversalPolyglotIgnoreInterpunction)
) -
Puppy over 11 yearsThey are, for all meaningful purposes, entirely identical to classes.
-
R. Martinho Fernandes over 11 years@XistenZ I don't know what your sources are, but rest assured, structs are as ugly as classes are. The only difference between the two is that one has public visibility by default, and the other has private.
-
XistenZ over 11 yearsSorry, didn't mean to offend anyone ^^ I meant ugly just visually, can't really explain how though.
-
Joseph Mansfield over 11 years@XistenZ Your edit does not explain what you did to fix it. Show what was wrong and the code that fixed it. Also, put the answer in your answer, not in the question. :) Thanks
-
cHao over 11 years@XistenZ: In C++, structs are classes. Literally, the only differences between a struct and a class are the default visibility (public for structs) and the use of
struct
rather thanclass
to declare the type. In every other respect, they are identical. Even inheritance, virtual functions, and all that classy stuff; structs can do all that too, identically. -
cHao over 11 yearsThe problem with this is that it forgets that, for example,
pet2
is aCat
. In this case it's not a huge deal, because the animals don't actually do much if anything. But later on, when aCat
includes custom behavior and properties, or if you want to squirrel one away in a vector or something, you'll experience the "slicing problem" firsthand. The correct answer involves figuring out why the pointer version breaks; it should not be as complicated as you're making it out to be. -
cHao over 11 yearsOr, declaring the function to take references. That'd be better than pointers, but still doesn't fix the reason why you're currently stuck passing
Animal
s by value. And you need to figure that out; with C++, you don't get polymorphism unless you access an object through a pointer or reference. Without polymorphism, subclasses become rather useless.