Thread: Pure Virtual Polymorphism HELP

  1. #1
    Registered User
    Join Date
    Aug 2010
    Location
    Rochester, NY
    Posts
    196

    Pure Virtual Polymorphism HELP

    Hey,

    I'm trying to use polymorphism as a type of generic/template, and it's exploding in my face bigtime.

    I have this class:
    Code:
    classA
    It's an abstract class. It has a function in it called:
    Code:
    virtual classA GetClass() = 0;
    classB inherits from classA with the following structure:
    Code:
    class classB : public classA
    {
    
    };
    In it I'd like to have a function that returns an instance of classB, ex.
    Code:
    classB GetClass();
    The caller will be thinking of it as an instance of classA, with all of the pure virtual functions implemented in classB.

    There's a problem, if I change the return type to the child class (like above), it thinks I'm trying to override it, yells, fails to compile.

    If I change the return type to classA (the parent), it realizes that this will instantiate a pure virtual / abstract class and pukes again.

    I know that you can use polymorphism this way, I've used it before to call "down" into a child class (basically one object is going to be using classB objects as if they were classA objects, as there's a bunch of pure virtual functions in classA). Though I've never had to RETURN a child class as if it was a parent class.

    As for the object using these classes, its prototype specifies classA, but it is passed classB, so it's not like I'm ever going to be instantiating pure virtuals.

    Anybody know how I can get this done? I know it's do-able, never had to return it, though, and my design was kind of dependent on it . Any help is greatly appreciated.

    EDIT:
    And obviously it goes without saying I can't change the prototype in classA to reflect the child class...

  2. #2
    -bleh-
    Join Date
    Aug 2010
    Location
    somewhere in this universe
    Posts
    463
    Quote Originally Posted by Syndacate View Post
    Hey,

    I'm trying to use polymorphism as a type of generic/template, and it's exploding in my face bigtime.

    I have this class:
    Code:
    classA
    It's an abstract class. It has a function in it called:
    Code:
    virtual classA GetClass() = 0;
    classB inherits from classA with the following structure:
    Code:
    class classB : public classA
    {
    
    };
    In it I'd like to have a function that returns an instance of classB, ex.
    Code:
    classB GetClass();
    The caller will be thinking of it as an instance of classA, with all of the pure virtual functions implemented in classB.

    There's a problem, if I change the return type to the child class (like above), it thinks I'm trying to override it, yells, fails to compile.

    If I change the return type to classA (the parent), it realizes that this will instantiate a pure virtual / abstract class and pukes again.

    I know that you can use polymorphism this way, I've used it before to call "down" into a child class (basically one object is going to be using classB objects as if they were classA objects, as there's a bunch of pure virtual functions in classA). Though I've never had to RETURN a child class as if it was a parent class.

    As for the object using these classes, its prototype specifies classA, but it is passed classB, so it's not like I'm ever going to be instantiating pure virtuals.

    Anybody know how I can get this done? I know it's do-able, never had to return it, though, and my design was kind of dependent on it . Any help is greatly appreciated.

    EDIT:
    And obviously it goes without saying I can't change the prototype in classA to reflect the child class...
    for the covariant type, you need to return either a pointer or reference to the derive class; returning by value will give compilation error
    Code:
    // this will compile
    class A {
    virtual A* func() = 0 ;
    }
    class B:public A
    {B* func();}
    // this will also compile
    class A {
    virtual A& func() = 0 ;
    }
    class B:public A
    {B& func();}
    
    
    //this wont
    class A {
    virtual A func() = 0 ;
    }
    class B:public A
    {B func();}
    Last edited by nimitzhunter; 01-09-2011 at 11:53 PM.
    "All that we see or seem
    Is but a dream within a dream." - Poe

  3. #3
    Registered User
    Join Date
    Aug 2010
    Location
    Rochester, NY
    Posts
    196
    Quote Originally Posted by nimitzhunter View Post
    for the covariant type, i think you need to return either a pointer or reference; returning by value will give compilation error
    Code:
    class A {
    virtual A* func() = 0 ;
    }
    class B:public A
    {B* func();}
    That bites. I can't just copy it? I'll give it a try none-the-less.

    EDIT:
    It works, WHY?

    (I hate everything about C++ less the STL)

    EDIT:
    I realize returning a ptr is much more efficient, but in this case I'd like to copy it back.
    Last edited by Syndacate; 01-09-2011 at 11:53 PM.

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Because this kind of polymorphism in C++ works through pointers and references.

    If you really want a copy, what you can do is to create a virtual clone() member function that acts like a virtual copy constructor (which otherwise cannot exist).
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    -bleh-
    Join Date
    Aug 2010
    Location
    somewhere in this universe
    Posts
    463
    Easiest way to think of it is that class A and B are not the same. but becuase of polymorphism, you can use pointer or reference of base class to point or refer to the derived class. That rules also apply to the return types.
    Just use the reference, if you don't like to use pointer.
    "All that we see or seem
    Is but a dream within a dream." - Poe

  6. #6
    Registered User
    Join Date
    Aug 2010
    Location
    Rochester, NY
    Posts
    196
    Quote Originally Posted by laserlight View Post
    Because this kind of polymorphism in C++ works through pointers and references.

    If you really want a copy, what you can do is to create a virtual clone() member function that acts like a virtual copy constructor (which otherwise cannot exist).
    Why does it only work with pointers? Simply because all pointers are created equal and it can pull its head out of its ass easier that way? This is something that should be do-able without the need to write anything extra.

    Quote Originally Posted by nimitzhunter View Post
    Easiest way to think of it is that class A and B are not the same. but becuase of polymorphism, you can use pointer or reference of base class to point or refer to the derived class. That rules also apply to the return types.
    They should be the same, though, that's why you have to call the constructor of the base class in the constructor for the child class, no? C++ merges objects up the inheritance chain as far as I know.


    ------------------SIDE NOTE:

    That was my simple "just get this working" example, I really wanted to return a vector of classB's (yes, I'm aware that's not the least bit efficient). So I simply wrapped each one in an STL vector and it puked. I changed all the pointer types to classA, and it works... So it works if I return classB in classB, even if the abstract parent class refers to it as classA, but if I want to use a template, I have to declare all of the pointers as classA.

  7. #7
    -bleh-
    Join Date
    Aug 2010
    Location
    somewhere in this universe
    Posts
    463
    They should be the same, though, that's why you have to call the constructor of the base class in the constructor for the child class, no? C++ merges objects up the inheritance chain as far as I know.
    Why should they? public inheritance is just a way to say that the base class becomes a public members of the derived class. consider this, instead of inheritance, i do this:
    Code:
    class classB{
    public:     
        classA x; 
    
       classB():x() {}
    }
    see that x is a classA type, but it's a public member of classB. and i still use its constructor in the constructor of classB. So are these two classes the same?
    "All that we see or seem
    Is but a dream within a dream." - Poe

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Syndacate
    Why does it only work with pointers? Simply because all pointers are created equal and it can pull its head out of its ass easier that way? This is something that should be do-able without the need to write anything extra.
    As I mentioned, it works through pointers and references. That said, where a reference is used, the implementation by the compiler is probably as if it were a pointer.

    For the question of why: there must be some kind of supertype reference that refers to an object of a subtype, thus the exact subtype can change at run time. Therefore, value semantics is unsuitable, but pointers and references in C++ have the suitable reference semantics to put this concept into action. If you use say, Java, you will find that the object types are actually reference types, hence there is no "need to write anything extra".
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Registered User
    Join Date
    Aug 2010
    Location
    Rochester, NY
    Posts
    196
    Quote Originally Posted by nimitzhunter View Post
    Why should they? public inheritance is just a way to say that the base class becomes a public members of the derived class. consider this, instead of inheritance, i do this:
    Code:
    class classB{
    public:     
        classA x; 
    
       classB():x() {}
    }
    see that x is a classA type, but it's a public member of classB. and i still use its constructor in the constructor of classB. So are these two classes the same?
    I have no idea, I've never seen code that looks like that. I mean it looks recursive as all hell. Assuming it's legal code and doesn't do any weird ........, it would lead one to believe that classB is part of the instance, not the class...but the instance is part of the class so I have no idea.

  10. #10
    Registered User
    Join Date
    Aug 2010
    Location
    Rochester, NY
    Posts
    196
    Quote Originally Posted by laserlight View Post
    As I mentioned, it works through pointers and references. That said, where a reference is used, the implementation by the compiler is probably as if it were a pointer.

    For the question of why: there must be some kind of supertype reference that refers to an object of a subtype, thus the exact subtype can change at run time. Therefore, value semantics is unsuitable, but pointers and references in C++ have the suitable reference semantics to put this concept into action. If you use say, Java, you will find that the object types are actually reference types, hence there is no "need to write anything extra".
    I phrased that poorly. I get why it works with pointers, what I don't get is why it doesn't work with objects.

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Syndacate
    I have no idea, I've never seen code that looks like that. I mean it looks recursive as all hell. Assuming it's legal code and doesn't do any weird ........, it would lead one to believe that classB is part of the instance, not the class...but the instance is part of the class so I have no idea.
    Notice that only composition is used. If you have really never seen code that looks like that then it is time to get a proper book and starting learning from the basics.

    Quote Originally Posted by Syndacate
    I get why it works with pointers, what I don't get is why it doesn't work with objects.
    The reason is that an object of type X is really just of type X. If Y is derived from X, and you assign an object of type Y to one of type X, then the part of Y that is not part of X will be sliced off.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    Registered User
    Join Date
    Aug 2010
    Location
    Rochester, NY
    Posts
    196
    Quote Originally Posted by laserlight View Post
    Notice that only composition is used. If you have really never seen code that looks like that then it is time to get a proper book and starting learning from the basics.
    Really? I'm not sure they'd have code like that in a 'basic c++ programming' book, and yeah, I've really never seen code like that...but I don't really think I need to 'go back to basics' to find it. It's some weird crap that people in the industry experience that I've been exposed to don't do, so I've never had to worry about it, if I did, I'd probably ask somebody there, or here, or somewhere.

    It looks like it just means that the sub class inherits from that 'instance' - but assuming it doesn't, not sure what it means or how it differs from 'normal' inheritance. Besides, it looks like it becomes a pain with long inheritance chains (ie. GUI frameworks), especially with multiple inheritance.

    Quote Originally Posted by laserlight View Post
    The reason is that an object of type X is really just of type X. If Y is derived from X, and you assign an object of type Y to one of type X, then the part of Y that is not part of X will be sliced off.
    Yeah, I guess that makes sense, and you can't use class X as the return type because it's pure virtual, therefore you could never instantiate something to be on the LHS to call the function on.

    Guess I just figured that I could use it like generics in that I'd like it (something in the caller function) to be handled as if it was the super class, but calling down to the sub-class functions when each function is called...which would mean I could just declare those functions inside the super as virtual, but without being pure virtual, it doesn't enforce implementation in the sub-class, is there any way around this? I'm assuming it'll just run into a compilation error.

  13. #13
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    What are you trying to do? If you are trying to limit the visibility of users of your objects then you can do so using paired interfaces and creating methods that return pointers that are the type of one side or the other.
    Last edited by VirtualAce; 01-11-2011 at 10:20 PM.

  14. #14
    Registered User
    Join Date
    Aug 2010
    Location
    Rochester, NY
    Posts
    196
    Quote Originally Posted by Bubba View Post
    What are you trying to do? If you are trying to limit the visibility of users of your objects then you can do so using paired interfaces and creating methods that return pointers that are the type of one side or the other.
    I was trying to make it so you can have 'plug-in' classes which implement from a common interface which enforces that the inheriting function implement some functions with the use of pure virtual functions. Since I wanted the logic to work with all of the 'plug-in' classes, they needed to be called as if it was the abstract class, then since it's virtual it'd call down to the sub class and call whichever function is actually being referenced.

  15. #15
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by Syndacate View Post
    I phrased that poorly. I get why it works with pointers, what I don't get is why it doesn't work with objects.
    To understand that, you need to understand set theory.

    The relationship between "base class" and "derived class" is not interchangeable. A class is just a category of object: a description of a particular set of objects.

    Class derivation represents subsetting. The set of objects represented by a derived class is a partial subset of the set of objects represented by the base class (not all objects of the base class are necessarily objects of the derived class).

    Class derivation simply represents relationships between categories of objects. All instances of a derived class are also instances of the base class. The reverse is not true. In the real world, all apples may be characterised as a fruit. But not all fruits may be characterised as an apple. An orange is a type of (or, in a class hierarchy, derived from) fruit, but an orange is not an apple.

    The only way two categories (or sets) of objects can be used completely interchangeably is if they are the same (i.e. they represent exactly the same set). If A is a subset of B, and B is a subset of A, then A and B are the same set of objects.

    Pointers and references, in C++, provide the defined means of going the other way (i.e. we have an apple, so we can do everything with it that we can do to a generic fruit). In C++-speak, a reference (or a pointer) to an apple can be implicitly converted into a reference to a fruit. However, since not all fruits are apples, a reference to a fruit cannot be implicitly converted into a reference to an apple.
    Last edited by grumpy; 01-13-2011 at 05:27 PM.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 10-28-2009, 09:25 AM
  2. Replies: 48
    Last Post: 09-26-2008, 03:45 AM
  3. Information Regarding Pure Virtual Functions
    By shiv_tech_quest in forum C++ Programming
    Replies: 6
    Last Post: 01-29-2003, 04:43 AM
  4. C++ XML Class
    By edwardtisdale in forum C++ Programming
    Replies: 0
    Last Post: 12-10-2001, 11:14 PM
  5. virtual or pure virtual
    By Unregistered in forum C++ Programming
    Replies: 1
    Last Post: 12-01-2001, 07:19 PM