Topic: Derived** cannot be converted implicitly to Base*const* . Why?
Author: "Silvio Bierman" <sbierman@idfix.nl>
Date: 2000/02/05 Raw View
Allowing it would introduce a hole in the type system:
struct A { };
struct B : A { };
struct C : A { };
B *pb = 0;
B**ppb = &pb;
A **ppa = ppb; /* this is not allowed, for good reasons... */
C *pc = new C;
A *pa = pc;
*ppa = pa;
/* At this point pb (which is a B*) points to the same C object pc points to
*/
Silvio Bierman
Niels Dekker wrote in message <389760B7.177D3E8A@NO_SPAM_PLEASEnki.nl>...
>(Sorry if this is a FAQ, but I have only found the answer for a
>pointer-to-NON-const-pointer-to-Base.)
>
>If Derived is a class that is public-derived from Base, why can't a
>Derived** argument be passed as Base*const* parameter?
>And when I have a function that works on an array of constant
>base-class-pointers, why can't I use it for an array of
>derived-class-pointers?
>
>// Example:
>class Person
>{
>public:
> virtual std::string GetName(void) const = 0;
>};
>
>class Programmer: public Person
>{
>public:
> std::string GetName(void) const;
>};
>
>void PrintNamesOfPersons(const Person* const ArrayOfPersons[]);
>Programmer* ArrayOfProgrammers[16];
>
>void Test(void)
>{
> PrintNamesOfPersons(ArrayOfProgrammers); // Error, but why?
>}
>
>Can you give an example wherein conversion from Derived** to
>Base*const* is harmful?
>
>Thank you in advance...
>
>Niels Dekker
>ndekker "at" nki "dot" nl
>
>---
>[ comp.std.c++ is moderated. To submit articles, try just posting with ]
>[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
>[ --- Please see the FAQ before posting. --- ]
>[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
>
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Niels Dekker <ndekker@NO_SPAM_PLEASEnki.nl>
Date: 2000/02/06 Raw View
Thanks to all of you for showing how the conversion I asked for might
lead to trouble if "Derived" has multiple base classes.
So if C++ didn't support multiple inheritence, it could have allowed
the implicit conversion from Derived** to Base*const*. Or not?
Anyway, I have the same problem in ObjectPascal (Delphi 5), even
though this language doesn't support mutual inheritence for classes.
(My ObjectPascal procedure has a const array of Base as parameter, but
cannot be used for an array of Derived.)
Valentin Bonnard wrote:
>
> Use a Base* const & instead of Base* const*, and you'll get
> the `` conversion '' from Derived*.
>
Nice suggesion, thanks! Of course that doesn't really help me when I
try to pass an array of Derived* as argument for an array of
Base*const parameter...
Silvio Bierman wrote:
>
> Allowing it would introduce a hole in the type system:
>
> struct A { };
> struct B : A { };
> struct C : A { };
>
> B *pb = 0;
> B**ppb = &pb;
>
> A **ppa = ppb; /* this is not allowed, for good reasons... */
>
You're right, but my question is about disallowing conversion to a
pointer-to-a-const-pointer-to-base-class:
A *const*ppa = ppb; // This is what I tries to do!
Have a good evening,
Niels Dekker
ndekker "at" nki "dot" nl
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 2000/02/07 Raw View
Niels Dekker wrote:
> So if C++ didn't support multiple inheritence, it could have allowed
> the implicit conversion from Derived** to Base*const*. Or not?
It _could_. It also could if we were ready to accept an
inefficient class representation, incompatible with the
one of C.
> Valentin Bonnard wrote:
> >
> > Use a Base* const & instead of Base* const*, and you'll get
> > the `` conversion '' from Derived*.
> >
> Nice suggesion, thanks! Of course that doesn't really help me when I
> try to pass an array of Derived* as argument for an array of
> Base*const parameter...
That's correct, it only works for single elements, not for arrays.
<ADVERTISING CLASS=exaggeration>Learn generic programming, the STL,
etc... and you won't ever have these problems.</ADVERTISING>
--
Valentin Bonnard
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Patrick Alberts" <Patrick@Alberts.org>
Date: 2000/02/09 Raw View
"Niels Dekker" <ndekker@NO_SPAM_PLEASEnki.nl> wrote in message
news:389760B7.177D3E8A@NO_SPAM_PLEASEnki.nl...
> If Derived is a class that is public-derived from Base, why can't a
> Derived** argument be passed as Base*const* parameter?
> And when I have a function that works on an array of constant
> base-class-pointers, why can't I use it for an array of
> derived-class-pointers?
As posted to comp.lang.c++ I have a similar problem. In the meantime, I've
used a rather crude solution, but it seems to work:
// first prepare our derived array of pointers
derived** ppDerived = new (derived*)[aNumber];
for( int i = 0; i < aNumber; ++i ) {
ppDerived[i] = new derived;
}
...
// some code
...
// now we want to call function work( base** ppBase )
// so I just re-interpret the array:
base** ppBase = new (base*)[aNumber];
for( int i = 0; i < aNumber; ++i ) {
ppBase[i] = (base*) ppDerived[i];
}
work( ppBase );
delete ppBase;
...
// some other code
...
// tidy up
for( int i = 0; i < aNumber; ++i ) {
delete ppDerived[i];
}
delete [] ppDerived;
This seems to work, but it's not very elegant. Is this correct or do I do
something really dangerous here?
pat!
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 2000/02/11 Raw View
Patrick Alberts wrote:
>
> ppBase[i] = (base*) ppDerived[i];
This shouldn't require a cast. Mindless casting like this
hides the type of type safety checking that C++ wants to do for
you.
But in general you are correct, if you have an array of derived*
and you want to convert to array of base* you must go through
and convert each element to be safe.
> delete ppBase;
Needs to be delete[], but you knew that, didn't you.
You could always use vectors and the "copy" templated operator.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Niels Dekker <ndekker@NO_SPAM_PLEASEnki.nl>
Date: 2000/02/02 Raw View
(Sorry if this is a FAQ, but I have only found the answer for a
pointer-to-NON-const-pointer-to-Base.)
If Derived is a class that is public-derived from Base, why can't a
Derived** argument be passed as Base*const* parameter?
And when I have a function that works on an array of constant
base-class-pointers, why can't I use it for an array of
derived-class-pointers?
// Example:
class Person
{
public:
virtual std::string GetName(void) const = 0;
};
class Programmer: public Person
{
public:
std::string GetName(void) const;
};
void PrintNamesOfPersons(const Person* const ArrayOfPersons[]);
Programmer* ArrayOfProgrammers[16];
void Test(void)
{
PrintNamesOfPersons(ArrayOfProgrammers); // Error, but why?
}
Can you give an example wherein conversion from Derived** to
Base*const* is harmful?
Thank you in advance...
Niels Dekker
ndekker "at" nki "dot" nl
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 2000/02/02 Raw View
Niels Dekker wrote:
> (Sorry if this is a FAQ, but I have only found the answer for a
> pointer-to-NON-const-pointer-to-Base.)
It isn't frequently asked.
> If Derived is a class that is public-derived from Base, why can't a
> Derived** argument be passed as Base*const* parameter?
A Derived* isn't representation-compatible with a Base* (a T*
is representation-compatible with a const T*).
Use a Base* const & instead of Base* const*, and you'll get
the `` conversion '' from Derived*.
--
Valentin Bonnard
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 2000/02/02 Raw View
Dave Abrahams wrote:
>
>
> It's because the physical address of a base class need not be the same as
> that of a derived class. Multiple-inheritance will illustrate this the
> quickest. Try some experiments with
>
> struct Base { int base; };
> struct X { int x; };
> struct Derived : X, Base {};
>
> and you'll probably see what's going on immediately.
Yep, he has two problems here (I missed the second for the first).
1. Can't convert
T** to const T**.
(Blows type safety see my other posting).
2. Can't convert
Derived** to Base**
Only know how to convert Derived* to Base*
(would have to changed *(Derived**) which would
hose anything still treating it as Derived*.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Dave Abrahams <abrahams@mediaone.net>
Date: 2000/02/03 Raw View
in article 389760B7.177D3E8A@NO_SPAM_PLEASEnki.nl, Niels Dekker at
ndekker@NO_SPAM_PLEASEnki.nl wrote on 2/2/00 4:10 PM:
> If Derived is a class that is public-derived from Base, why can't a
> Derived** argument be passed as Base*const* parameter?
> And when I have a function that works on an array of constant
> base-class-pointers, why can't I use it for an array of
> derived-class-pointers?
It's because the physical address of a base class need not be the same as
that of a derived class. Multiple-inheritance will illustrate this the
quickest. Try some experiments with
struct Base { int base; };
struct X { int x; };
struct Derived : X, Base {};
and you'll probably see what's going on immediately.
-Dave
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 2000/02/03 Raw View
Niels Dekker <ndekker@NO_SPAM_PLEASEnki.nl> writes:
>If Derived is a class that is public-derived from Base, why can't a
>Derived** argument be passed as Base*const* parameter?
The conversion from Derived* to Base* might require
a change in value or representation. For example,
that is often necessary in cases where multiple inheritance
is involved. To convert from a Derived* to a Base*, the compiler
may need to add the offset of the Base class within the Derived
class object.
This means that you can't just reinterpret the bits of a Derived*
as if it were a Base*. So, regardless of the const, a pointer
to Derived* is not the same as a pointer to Base*.
>Can you give an example wherein conversion from Derived** to
>Base*const* is harmful?
#include <iostream>
struct Base1 { int x; };
struct Base { int y; };
struct Derived : Base1, Base { };
int main() {
Derived d;
d.x = 100;
d.y = 42;
Derived *pd = &d;
Derived **ppd = &pd;
Base *const*pcpb = (Base*const*) ppd;
std::cout << (*pcpb)->y << std::endl; // undefined behaviour
// typically outputs `100', not `42'.
}
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 2000/02/03 Raw View
This is in the C++ FAQ. It's never safe to convert T** to const T**.
(Doesn't have anything to do with the Derived to Base part of the
conversion).
T* tp;
T** tpp = &tp; // Legit.
const T** ctpp = tpp; // Presume this is legal (it's not).
const T ct;
*ctpp = &ct; // legal: const T* = const T*
// Note at this point we still have tp of type T*
// and it now has the value of &ct of type const T*
*tp = T(); // BOOM, modified a const object
// without having to force it with
// a cast!
The way to do this is to change the ctpp definition to be:
const T* const* ctpp = tpp; // Now legal.
*ctpp = &ct; // BOGUS! *ctpp is const.
Which allows you do what you probalbly want but elimiates type games.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: =?ISO-8859-1?Q?J=F6rg?= Barfurth <joerg.barfurth@germany.sun.com>
Date: 2000/02/03 Raw View
Am 02.02.00, 16:10:19, schrieb Niels Dekker
<ndekker@NO_SPAM_PLEASEnki.nl> zum Thema Derived** cannot be converted
implicitly to Base*const* . Why?:
> If Derived is a class that is public-derived from Base, why can't a
> Derived** argument be passed as Base*const* parameter?
> And when I have a function that works on an array of constant
> base-class-pointers, why can't I use it for an array of
> derived-class-pointers?
A Derived* need not have the same value representation as a Base*
pointing to its Base base class subobject. This is especially
obvious in case of multiple inheritance.
The only way a Derived** could be converted to a Base** (whatever
qualifiers are present) would have the result of the conversion
pointing at the same memory as the original pointer (in most
implementations a reinterpret_cast will do this).
There is no guarantee that the contents of that memory can be validly
interpreted as Base* much less that such interpretation would yield a
pointer to the Base base class subobject of the Derived object
originally pointed to.
> Can you give an example wherein conversion from Derived** to
> Base*const* is harmful?
struct A { std::string s; virtual void foo(double); };
struct Base { mutable int i; virtual double bar(char) const; };
struct Derived : A, Base {};
void f(Base const * const * ppb)
{
(**ppb).i = 42;
(**ppb).bar('x');
}
void g(Derived** ppd)
{
f(ppd); // ERROR
// f(reinterpret_cast<Base**>(ppd));
}
Uncommenting the second line in g() considered harmful.
In my implementation the first line of f will overwrite internals of
the A::s string object in (**ppd).
The second line will damage the stack if A::foo() hasn't crashed
before that.
--
J rg Barfurth
joerg.barfurth@germany.sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]