I can't understand anything here. I expected that if I can pass a dog pointer to function taking animal pointer, I could also pass the &dog to a function that takes a pointer to pointer of Animal.
struct Animal{};
struct Dog : Animal{};
void ptrToPtr(Animal** arg){}
void refToPtr(Animal*& arg){}
void refToConstPtr(Animal* const & arg){}
void ptrToConstPtr(Animal* const * arg){}
int main(void)
{
Dog* dog;
Animal* animal;
ptrToPtr(&animal); // Works
ptrToPtr(&dog); // Argument of type Dog** is incompatible with argument of type Animal**
refToPtr(animal); // Works
refToPtr(dog); // A reference of type Animal*& (not const-qualified) cannot be initialized with a value of type Dog*
ptrToConstPtr(&animal); // Works
ptrToConstPtr(&dog); // Argument of type Dog** is incompatible with paramater of type Animal* const*
refToConstPtr(animal); // Works
refToConstPtr(dog); // Works. This is the only one that allows me to send Dog to Animal
return 0;
}
I just don't get it, can anyone explain what the reasons are for why particular cases work and others don't? Like passing the dog pointer address to the Animal**, that would be an upcast, wouldn't it?
interconvertible pointer types are pointers to objects of a derived/base type. A "pointer to a pointer" isn't interconvertible with other types (with the exception of void*
). Same applies to references.
This means that given any hierarchy below:
struct Animal{};
struct Dog : Animal{};
And the following variables:
Dog* dptr;
Animal* aptr;
dptr
can be converted to Animal*
(even implicitly), likewise aptr
can be converted to Dog*
(but not implicitly). Because: up-casting in a class hierarchy is always legal, hence this will be done implicitly by ICS . However, down-casting isn't always so, so its never done implicitly)
However:
Dog** ddptr;
Animal** aaptr;
ddptr
cannot be implicitly converted to Animal**
, likewise aptr
cannot be converted to Dog**
. Because, they are two different types with no hierarchical relationship.
The above explanation explains why the pointer to pointer overloads fail. That said, let's deal with the reference type overloads. From your code,
refToPtr(animal); // Works
refToPtr(dog); // A reference of type Animal*& (not const-qualified) cannot be initialized with a value of type Dog*
the second call doesn't work because non-const references of say X
can only be bound to an exact glvalue object of X
. Since refToPtr
takes a non-const reference to a Animal*
type, we can only pass it glvalues of Animal*
type, which animal
is, but dog
isn't.
the last one works, and it's legal because
refToConstPtr(animal); // Works
refToConstPtr(dog); // Works. This is the only one that allows me to send Dog to Animal
const
references of say X
can be bound to any value catagory of X
, including temproaries whose lifetimes are extended. Since since we can convert dog
to Animal*
. That conversion takes place and a temporary Animal*
is produced whose lifetime is extended by the const
reference.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.