Re: CPtrList - Please Help me understand

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

From: Joseph M. Newcomer (newcomer_at_flounder.com)
Date: 09/01/04


Date: Wed, 01 Sep 2004 04:37:17 -0400

I meant to add, you would have been better off declaring your own CList, e.g.,
        CList<notice *, notice *>notices;
instead of
        CPtrList notices;

then all of this disappears, and you can ignore it, because the GetAt() will return an
object of type notice*, and you won't need to do casts at all.
                                        joe

On Tue, 31 Aug 2004 17:54:26 -0400, Joseph M. Newcomer <newcomer@flounder.com> wrote:

>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

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: 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: Why MFC doesnt like /vmg?
    ... These options select the method that the compiler uses to represent pointers ... to specify a pointer representation. ... before you declare a pointer to a member of the class. ... pointer to a member of a class before defining the class. ...
    (microsoft.public.vc.mfc)
  • Re: Function pointer question P119 K&R
    ... representation and alignment requirements as a pointer to a character ... the compiler knowing what the function expects. ... then any void* whose value is properly aligned for the object ...
    (comp.lang.c)
  • Re: Pointer equality and dereferencing
    ... representation using some non-trivial algorithm. ... compiler might mistake it for a pointer that points to one past some array ... definition outside the scope of the standard, ...
    (comp.std.c)
  • Re: How to convert Infix notation to postfix notation
    ... and make all strings const save where the intent ... function whose contract is to change the string. ... the compiler "just" prevents the string ... try to do using the pointer you get. ...
    (comp.lang.c)