Re: CPtrList - Please Help me understand

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance

From: Joseph M. Newcomer (newcomer_at_flounder.com)
Date: 08/31/04


Date: Tue, 31 Aug 2004 17:54:26 -0400

Depends on what sort of object you are storing things in. Since you have a CPtrList, it
holds generic pointers, of type void *. This means that GetAt() returns only a void *,
which cannot be stored into a variable of any other type. Thus you could write

void * temp = m_list.GetAt(pos);

and the compiler would be happy. But the rules of C++ do not permit taking a pointer of a
higher class (void * is the "root class" of all other classes) and assigning it to a
specialized subclass. This is just a special case of

class A { ... };
class B : public A { ... }

B * bp = new B;
A * ap = bp; // valid
B * bp2 = ap;

Now although bp has a pointer to an object of type B (which we know because we created
one), and it is valid to assign it to an A* (because all Bs are As), the third assignment
is invalid by the rules of C++ because it doesn't know if the thing in ap is a B or an A.
Note that if we did

class C : public A { ... }

it would be valid to do
A * ap = new C;
but then it would be nonsensical to do
B * bp2 = ap;
because the thing in A, although it is an A, and a C, is not a B.

There are several ways to handle this. The simplest method is to do

B * bp2 = (B *)ap;

the construct (type)expression tells the compiler to treat expression as if it were
(type), and not whatever it turns out to be.

So although ap is an A*, you insist to the compiler that it is really a B*, so the
compiler now happily does the assignment.

The only problem with this is with the class C. Suppose I did

A * ap = new C;
B * bp2 = (B*)ap;

the compiler is happy, it does what it is supposed to, and does essentially an illegal
assignment, because the thing in ap is in fact NOT a B*, but a C*!

Many people are offended by this. Unforutnately, the solution is somewhat clumsy, but is a
better solution. You would write

B * bp2 = dynamic_cast<B *>ap;

which forces a runtime check of the object referenced by ap. If it is of type B*, the
assignment takes place; if it is not of type B* (such as being a C*) then the NULL pointer
value is assigned to bp2, which you can then check. This is known as a "safe cast-down",
since it casts the type to a type which is lower in the type hierarchy, and does so
safely.

The shorter form is more convenient to use, and does not require run-time-type-information
(RTTI) to be enabled, but is, in fact, potentially unsafe. The form
        (B*)ap
is the same as
        static_cast<B*>ap

Generally, casting has no effect on the representation of a value, other than instructing
the compiler to trust you. So in 32-bit windows (and this is poor practice but it
illustrates a point)
        DWORD w = (DWORD)ap;
takes the pointer ap which is a 32-bit value, and tells the compiler to treat it as a
DWORD (integer value) in terms of type checking (the reason this is poor practice is that
with the introduction of 64-bit machines, a pointer is now 64 bits and a DWORD is 32 bits)
so the correct representation would be
        DWORD_PTR w = (DWORD_PTR)ap;
because a DWORD_PTR is an integer type big enough to hold a pointer, but otherwise behaves
as an integer, but you don't need to worry about this until you get more advanced.

But this rule falls apart with the casts between integer values and floating-point values.
So

double d = 2.95;
int n = (int)d;
double p = (double)n;

actually DOES change the representation. In the first case, where d is being assigned to
n, the floating-point representation 2.1, which is 64 bits with a mantissa and exponent
component, is converted to an integer (discarding the .95! It doesn't round!) is converted
to the integer 2. In the second case, where n is being assigned to p, the 32-bit integer
value is converted to a 64-bit floating-point value with a mantissa and exponent
representation, which is quite different.

Note that if you saw the value 3, it might have been 2.99999999999999 internally, but
printed as 3, so where you do
        int n = (int)d;
you will actually get the number 2, not 3. The solution to this is to write, if you want
to be reasonably accurate and have rounding handled properly,
        int n = (int) (d < 0 ? d - 0.5 : d + 0.5)
which does the correct rounding to the expected integer value.
                                joe

On 31 Aug 2004 12:28:56 -0700, victor75040@yahoo.com (victor) wrote:

>Hi All,
>
>I have a tutorial where I am trying to understand something, I have a
>fairly good grip as to how pointers work. Here is what I have.
>
>Struct notice
>{
> CString notedata;
> int numberofdata;
>}
>
>I also have a CPtrList object m_list, to wich I have added several
>nodes of the
>type Struct notice.
>
>Now the tutorial shows the line below:
>
>notice *temp = (notice *) m_list.GetAt(pos);
>
>I understand the part left of the = sign means create a pointer var
>temp of the type notice, but I am having a diffcult time understanding
>the part (notice *) to the right of the = sign. Can someone please
>break this down and explain is simple term. I understand the
>m_list.GetAt(pos) part, just the (notice*) is confusing the heck out
>of me.
>
>Thanks
>
>Victor
>victor75040@yahoo.com

Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm



Relevant Pages

  • Re: CPtrList - Please Help me understand
    ... object of type notice*, and you won't need to do casts at all. ... >Now although bp has a pointer to an object of type B (which we know because we created ... >compiler now happily does the assignment. ... >Generally, casting has no effect on the representation of a value, other than instructing ...
    (microsoft.public.vc.mfc)
  • Re: Proper way to check malloc return
    ... I'd say that any compiler that gets that wrong is not a C compiler, ... the internal representation of a null pointer is or isn't all-bits-zero. ... an implicit conversion of ptr to some integral type. ...
    (comp.lang.c)
  • Re: Adding gpib support to Matlab on Linux ?
    ... gpib.c:219: warning: assignment makes pointer from integer without a cast ...
    (comp.soft-sys.matlab)
  • Re: array subscript type cannot be `char`?
    ... "add any integer to pointer". ... Now, for through above, the compiler is probably forced to ... In particular, in assignment 6, the compiler is allowed to "know" ... might want to use 16-bit addition to address "small" arrays (with ...
    (comp.lang.c)
  • compiling dcraw, a raw file to ppm convertor
    ... dcraw.c:479: warning: assignment makes pointer from integer without a cast ...
    (comp.sys.sgi.admin)