Like Tree4Likes

Widening and Narrowing concepts

This is a discussion on Widening and Narrowing concepts within the C++ Programming forums, part of the General Programming Boards category; Originally Posted by iMalc Because you're doing the same thing as was mentioned in tabstop's post. In your case 'a' ...

  1. #16
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    Quote Originally Posted by iMalc View Post
    Because you're doing the same thing as was mentioned in tabstop's post. In your case 'a' is only a Shape, not a Square.
    You can't turn a Shape into a Square (unless there is a Square constructor that takes a shape, that is).

    'b' however, points to a Square so casting it to Square* is all fine and dandy. Bear in mind though that it doesn't know for sure that what you're telling it is correct. It just blindly casts the pointer and if it happened to point to a Hexagon say, then something will may go wrong later when you try and use it. The safer way to do that cast is to use dynamic_cast.

    With the last line assigning to q, you're dereferencing the Shape* pointer 'b', and so it thinks you're trying to copy a Shape into a Square again. The polymorphism only works so long as you are dealing with method calls through a pointer, or doing rtti queries with the pointer, but once you dereference to get the actual object then it will be of the type that the pointer says it is.
    Ah, yes..so that was what that bloody error was.
    *Penny in the air*

    Let me try to explain it IMOW...
    Because a Square IS A Shape..I can store the bloody square in the Shape object. What happens is the base constructor is first called (If I remember correctly, it said so in the Deitel book). It copies the data members and member functions into the Shape object...but instead of calling the Square constructor it doesn't like tabstop said...so the only thing left in Shape a is a Shape object...the compiler implicitly does it.
    But when I try to do the reverse, a Shape IS NOT A Square..and its base constructor is not a Square (although if I am really evil I could lie to the compiler)..but if I really wanted to do it I must explicitly provide a copy constructor in the Square class and that should solve the problem.

    *Did the penny drop?*
    The polymorphism only works so long as you are dealing with method calls through a pointer, or doing rtti queries with the pointer
    What is Rtti? Run time type...?
    but once you dereference to get the actual object then it will be of the type that the pointer says it is.
    In this case the type being Shape, not Square...but if it the function was virtual..it'd be Square? Ha ha *rolls eyes*

    Is it impossible to downcast in C++?
    I tried this without assigning it
    ((Square)a).draw() ;
    I would have thought that was possible..I must be doing something wrong, I am sure my lecturer did something like this before.
    EDIT:
    Oh yeah, it works like this
    Code:
        (dynamic_cast<Square*>(b))->draw(); //or
        ((Square*)b)->draw() ;
    Last edited by Eman; 09-04-2011 at 05:41 AM.
    You ended that sentence with a preposition...Bastard!

  2. #17
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,820
    Forget downcast and upcast. They only work with pointers. They basically tell the compiler to treat what the pointer points to as a different type.
    When you don't have a pointer, you are working with objects.

    A circle may be a shape, but a shape is not necessarily a circle! It is the same as an apple is a fruit, but a fruit is not necessarily an apple!
    What you are doing is telling the compiler "I want you to create a new circle from this shape," not "I want you to interpret this shape as a circle." The later is only possible with pointers.
    And since the compiler does not known how to create a circle from a shape (no copy constructor!), it fails.

    RTTI stands for Runtime Type Information.
    If you want to downcast an object on the stack, you can use this nasty hack:

    dynamic_cast<Square*>(&a)->draw();
    Last edited by Elysia; 09-04-2011 at 06:59 AM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  3. #18
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    Quote Originally Posted by Elysia View Post
    Forget downcast and upcast. They only work with pointers. They basically tell the compiler to treat what the pointer points to as a different type.
    When you don't have a pointer, you are working with objects.

    A circle may be a shape, but a shape is not necessarily a circle! It is the same as an apple is a fruit, but a fruit is not necessarily an apple!
    What you are doing is telling the compiler "I want you to create a new circle from this shape," not "I want you to interpret this shape as a circle." The later is only possible with pointers.
    And since the compiler does not known how to create a circle from a shape (no copy constructor!), it fails.

    RTTI stands for Runtime Type Information.
    If you want to downcast an object on the stack, you can use this nasty hack:

    dynamic_cast<Square*>(&a)->draw();
    But casting Shape object into Square object should not call the copy constructor...I thought it was using the assignment operator that called the copy constructor of Square..apparently not.

    EDIT:
    Code:
     ((Square&)b).draw() ;
    That also works...as long it is a pointer or reference to a lower hierarchy object, downcasting works...
    This will be a struggle to remember what I just learnt
    Last edited by Eman; 09-04-2011 at 08:46 AM.
    You ended that sentence with a preposition...Bastard!

  4. #19
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,820
    Yes, it should.
    The line

    (a)b

    tells the compiler to create a temporary object of type a, and initialize it with the object b.
    This is always true, even with pointers.

    (a*)b

    where b is a pointer tells the compiler to create a temporary object (pointer) of type a* and initialize it with b.
    For pointers this obviously works since that operation is perfectly defined by built-in rules. But with custom objects, it doesn't work fine because the compiler does not know how to do it.

    Also separate initialization with assignment. Initialization calls the copy constructor and assignment calls the assignment operator.

    A a(b);
    A a = b;

    Are examples of initialization.

    A a;
    a = b;

    Is an example of assignment.
    Eman likes this.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #20
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    Quote Originally Posted by Elysia View Post
    Yes, it should.
    The line

    (a)b

    tells the compiler to create a temporary object of type a, and initialize it with the object b.
    This is always true, even with pointers.
    Oops...I didn't know that..so which means when I do this..
    Square a = (Square)b ; //b being Shape b = Square()..type slicing occurs so it is a Shape object.
    Temp object is created, tries to copy b into a..Fails, no copy constructor for storing a Shape into a Square...But if b was a Square..that means copying takes place twice? Mmn, thanks for pointing that out.

    (a*)b

    where b is a pointer tells the compiler to create a temporary object (pointer) of type a* and initialize it with b.
    For pointers this obviously works since that operation is perfectly defined by built-in rules. But with custom objects, it doesn't work fine because the compiler does not know how to do it.
    copying a reference into another reference doesn't need the copy constructor to be called.
    But the compiler follows rules to add the member functions and data to that temporary reference.. What is this called? Opposite of slicing..is there a term for it?

    Also separate initialization with assignment. Initialization calls the copy constructor and assignment calls the assignment operator.

    A a(b);
    A a = b;

    Are examples of initialization.

    A a;
    a = b;

    Is an example of assignment.
    Thanks, I do confuse the 2
    Last edited by Eman; 09-04-2011 at 09:09 AM.
    You ended that sentence with a preposition...Bastard!

  6. #21
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,820
    Quote Originally Posted by Eman View Post
    Oops...I didn't know that..so which means when I do this..
    Square a = (Square)b ; //b being Shape b = Square()..type slicing occurs so it is a Shape objects.
    Temp object is creates, tries to copy b into a..Fails, no copy constructor for storing a Shape into a Square...But if b was a Square..that means copying takes place twice? Mmn, thanks for pointing that out.
    Actually, the part (Square)b is what fails, because that's where the compiler would try to create a temporary and call the copy constructor for Square(const Shape&), which doesn't exist.
    The assigning of a square to a square is perfectly defined.
    Technically, copying takes place twice with
    Square a = (Square)b;
    where b is a Square or any type convertible to Square.

    copying a reference into another reference doesn't need the copy constructor to be called.
    But the compiler follows rules to add the member functions and data to that temporary reference.. What is this called? Opposite of slicing..is there a term for it?
    This isn't a reference (a reference is not a pointer!), and secondly, no, it does nothing of the sort.
    These are pointers we're working with, so the compiler copies over the address.
    If they were not pointers, then the compiler would create a new object, then invoke the copy constructor to copy over data.
    If we had

    Shape a = b;

    Where b is a Square, then slicing would occur.
    The best way to see this is that Square is implicitly convertible to const Shape&, which is a copy constructor that already exists in Shape, implicitly or explicitly. This copy constructor would copy over all the data from the Shape portion of the object (since it is unaware that it may actually be Square).

    Other than that, I don't know what you mean.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #22
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    Quote Originally Posted by Elysia View Post
    Actually, the part (Square)b is what fails
    Huh, must it not create a temp object before it can copy another compatible object into it. I really can't see it :O


    This isn't a reference (a reference is not a pointer!)
    Sorry, but there really isn't a difference though ha ha
    , and secondly, no, it does nothing of the sort.
    These are pointers we're working with, so the compiler copies over the address.
    Yes, I agree...but Square *a would think it was pointing to a valid Square object..which it doesn't..
    So how how is that when I do
    ((Square&)a).bounce() assuming bounce is a member function of only Square..that would work? This is what I was asking..does the compiler know to look for it or something and does early binding.
    You ended that sentence with a preposition...Bastard!

  8. #23
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,820
    Quote Originally Posted by Eman View Post
    Huh, must it not create a temp object before it can copy another compatible object into it. I really can't see it :O
    Technically, yes, but what I mean is that you can break this into multiple statements:

    Square tmp = b;
    Square a = b;

    The first line will fail, but the second will compile.


    Sorry, but there really isn't a difference though ha ha
    There is a huge difference. References are an entirely different feature and concept.

    Yes, I agree...but Square *a would think it was pointing to a valid Square object..which it doesn't..
    So how how is that when I do
    ((Square&)a).bounce() assuming bounce is a member function of only Square..that would work? This is what I was asking..does the compiler know to look for it or something and does early binding.
    You are creating a temporary reference of type square to a, which is a Square, which has the member function bounce. What is so surprising here?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #24
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    Quote Originally Posted by Elysia View Post
    Technically, yes, but what I mean is that you can break this into multiple statements:

    Square tmp = b;
    Square a = b;

    The first line will fail, but the second will compile.
    Square a = b; should fail as well? b is a Shape object....

    There is a huge difference. References are an entirely different feature and concept.
    What I meant was that it does the same, which isn't really that new...

    You are creating a temporary reference of type square to a, which is a Square, which has the member function bounce. What is so surprising here?
    a isn't of type Square..it is a Shape after type slicing occurs..so member function bounce should have been discarded....isn't that the theory.
    isn't a square..it is a Shape after type slicing occurs..so member function bounce should have been discarded....isn't that the theory?
    So after the reference has been created and I try to access an actual Shape object..why is that bounce() miraculously appears?
    You ended that sentence with a preposition...Bastard!

  10. #25
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,820
    Quote Originally Posted by Eman View Post
    Square a = b; should fail as well? b is a Shape object....
    Good catch. That was a typo.
    It should be
    Square a = tmp;

    What I meant was that it does the same, which isn't really that new...
    It does not do the same thing, it does not work the same way and is fundamentally different from pointers. Separate the concepts!

    a isn't of type Square..it is a Shape after type slicing occurs..so member function bounce should have been discarded....isn't that the theory.
    isn't a square..it is a Shape after type slicing occurs..so member function bounce should have been discarded....isn't that the theory?
    So after the reference has been created and I try to access an actual Shape object..why is that bounce() miraculously appears?
    Yeah, OK, so here is the thing.
    The C++ compiler works only on type information. It does not have any meta data information.
    It does not know what type the actual object is, only what type you are telling it it is.
    That is, the type of the variable is what type the compiler assumes it is.
    So if a really is a Shape, then what the line does is "hey compiler, I want this to be a reference to a Square, and I want you to access its member bounce."
    The compiler will obey you and try doing it. What actually happens is anyone's guess, because it's undefined territory.

    Also, tools are dumb is the same sense, as well. You are telling it to treat the type as a Square when it really isn't, and it's just happy to oblige.
    Eman likes this.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #26
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    Quote Originally Posted by Elysia View Post
    Good catch. That was a typo.
    It should be
    Square a = tmp;
    Thanks, but I still think the compiler error occurs when it tries to copy b into tmp..but before copying tmp would've been pushed onto the stack.

    It does not do the same thing, it does not work the same way and is fundamentally different from pointers. Separate the concepts!
    Ok maybe it doesn't follow the same rules..but at the end of the day..it does what pointers are trying to do in a neater and easier way for dumb dumb like me :P

    Yeah, OK, so here is the thing.
    The C++ compiler works only on type information. It does not have any meta data information.
    It does not know what type the actual object is, only what type you are telling it it is.
    That is, the type of the variable is what type the compiler assumes it is.
    So if a really is a Shape, then what the line does is "hey compiler, I want this to be a reference to a Square, and I want you to access its member bounce."
    The compiler will obey you and try doing it. What actually happens is anyone's guess, because it's undefined territory.

    Also, tools are dumb is the same sense, as well. You are telling it to treat the type as a Square when it really isn't, and it's just happy to oblige.
    Bloody ashes, that was what I wanted to hear...what took you so long? :O
    You ended that sentence with a preposition...Bastard!

  12. #27
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,820
    Quote Originally Posted by Eman View Post
    Thanks, but I still think the compiler error occurs when it tries to copy b into tmp..but before copying tmp would've been pushed onto the stack.
    But since the compiler cannot actually copy the contents, it won't generate any code for it. So you may think of that as you like.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #28
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    Quote Originally Posted by Elysia View Post
    But since the compiler cannot actually copy the contents, it won't generate any code for it. So you may think of that as you like.
    Dang you are right...some day Elsyia, some day!
    Btw thanks for your help, as the others.
    You ended that sentence with a preposition...Bastard!

Page 2 of 2 FirstFirst 12
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. C++0x Concepts fall
    By Mario F. in forum General Discussions
    Replies: 32
    Last Post: 07-27-2009, 02:31 AM
  2. Need help with concepts for first game
    By blankstare77 in forum Game Programming
    Replies: 29
    Last Post: 10-01-2005, 08:53 AM
  3. Programming concepts
    By lyx in forum C++ Programming
    Replies: 2
    Last Post: 12-02-2003, 11:37 PM
  4. Java Concepts
    By mart_man00 in forum Tech Board
    Replies: 11
    Last Post: 09-04-2003, 05:14 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21