Passing a derived class where base class is defined as ref parameter

Mike Parker aldacron at gmail.com
Tue Dec 14 07:33:53 UTC 2021


On Monday, 13 December 2021 at 22:06:45 UTC, chopchop wrote:

> If I remove the ref, it works as expected, that is to say I can 
> give a derived class as parameter. I have an idea why it does 
> not work, but I think a c++ reference would work, ie incr(A& 
> console) would accept a B as parameter. What the logic here?

TL:DR it's because there are two levels of indirection.

What's happening here is that `ref A` in D *is not* equivalent to 
`A&` in C++. That's because D classes are reference types like 
Java classes, not value types like C++ classes. Your `b` is a 
handle to an instance, not an instance itself. It's more akin to 
`B*` in C++. So that means that your `ref A` is like `A**` in 
C++. And I believe you'll find that `B**` in C++ is not 
implicitly convertible to `A**`.

Since `ref` in D is just a pointer under the hood, we can be more 
explicit like so:

```d
void incr(A* a)
{
     writeln(a.i);
}

B b = new B();
incr(&b);
```

In this case, compilation also fails. `B*` is not implicitly 
convertible to `A*`. Again, this is equivalent to `B**` and `A**` 
in C++.

In this case, you can explicitly do the conversion with a cast: 
`incr(cast(A*)&b);`

But consider what happens in this case:

```d
void incr(A* a)
{
     *a = new A;
}

B b = new B();
incr(cast(A*)&b);
writeln(b.j);
```

Your `b` is no longer a `B`, but still thinks it is.

This is my understanding of why implicit conversion is disallowed 
when multiple levels of indirection are involved.


More information about the Digitalmars-d-learn mailing list