16

Regarding the following C++ program:

class Base { };

class Child : public Base { };

int main()
{   
    // Normal: using child as base is allowed
    Child *c = new Child();
    Base *b = c;

    // Double pointers: apparently can't use Child** as Base**
    Child **cc = &c;
    Base **bb = cc;

    return 0;
}

GCC produces the following error on the last assignment statement:

error: invalid conversion from ‘Child**’ to ‘Base**’

My question is in two parts:

  1. Why is there no implicit conversion from Child** to Base**?
  2. I can make this example work with a C-style cast or a reinterpret_cast. Using these casts means throwing away all type safety. Is there anything I can add to the class definitions to make these pointers cast implicitly, or at least phrase the conversion in a way that allows me to use static_cast instead?
curiousguy
  • 8,038
  • 2
  • 40
  • 58
Mike Mueller
  • 2,072
  • 15
  • 16
  • 1
    Variations on this question in many programming languages is one of the most common questions on SO. But everyone phrases it slightly differently even for the same language, so finding duplicates can be difficult. – Daniel Earwicker Mar 28 '10 at 09:33
  • 1
    "Fixing" this example to avoid shady casts will depend on why you are using a pointer-to-pointer in the first place. – aschepler Jul 24 '12 at 18:52

2 Answers2

27

If this was allowed, you could write this:

*bb = new Base;

And c would end up pointing to an instance of Base. Bad.

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
  • Small correction - he could say `**bb = new Base();` Just `*bb` wouldn't be allowed. – Phil Mar 28 '10 at 09:38
  • 4
    @Phil: `new` returns a pointer, which is type `*Base`. `bb` is of type `**Base`. Thus `*bb` is the right level of dereference. – Amber Mar 28 '10 at 09:43
  • 1
    The rationale is essentially the same as the comp.lan.g.c FAQ about the non-equivalence of `char**` and `char const**`: http://c-faq.com/ansi/constmismatch.html – Michael Burr Mar 28 '10 at 10:30
  • @Dav: sorry, I was assuming you replaced the line `Base **bb = cc`, with `Base **bb = new Base()`. Don't know where I got that idea though, since if I thought that, your `Base *b = new Base()` would be perfectly legal. My mistake! – Phil Mar 28 '10 at 11:21
  • (bow) Simple and clear, and saved today's logic-bepuzzling-quota for other problems. :) – david van brink Sep 01 '14 at 19:52
1

Pointers are virtual address. Normally you are responsible for what you do with it. Using msvc 2019. I can cast one to base, but not two:

example 1:

int p;
int *p1 = &p;
int **p2 = &p1; //OK

example 2:

struct xx {};
struct yy : public xx {};

yy p;
yy *p1 = &p;
xx **p2 = &p1; //Just a strange error

example 3:

struct xx {};
struct yy : public xx {};

yy p;
xx *p1 = &p; 
xx **p2 = &p1; //OK
boboid
  • 11
  • 2