Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. I thought I understood polymorphism

I thought I understood polymorphism

Scheduled Pinned Locked Moved C / C++ / MFC
c++oophelp
9 Posts 5 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    Alex Griffing
    wrote on last edited by
    #1

    The wrong function is getting called. I believe it goes like this: class foo { public: inline foo() { bar(); } virtual bar(); }; class fooplus : public foo { public: inline fooplus() : foo() {}; virtual bar(); } The problem is that when I instantiate fooplus, foo::bar gets called instead of fooplus::bar. I believe that if you said fooplus fooinst; fooinst.bar(); then it would call foo::bar and then fooplus::bar. I'm trying to use more of the power of C++, but stuff like this is making me want to just use it like C with member functions like I used to. :(

    A B M 3 Replies Last reply
    0
    • A Alex Griffing

      The wrong function is getting called. I believe it goes like this: class foo { public: inline foo() { bar(); } virtual bar(); }; class fooplus : public foo { public: inline fooplus() : foo() {}; virtual bar(); } The problem is that when I instantiate fooplus, foo::bar gets called instead of fooplus::bar. I believe that if you said fooplus fooinst; fooinst.bar(); then it would call foo::bar and then fooplus::bar. I'm trying to use more of the power of C++, but stuff like this is making me want to just use it like C with member functions like I used to. :(

      A Offline
      A Offline
      Alex Griffing
      wrote on last edited by
      #2

      I'm working around it by putting everything except the call to the overridden function in a new member function (Init). This way it works, but both constructors have the same code. foo() { init(); //foo::init() bar(); //foo::bar() } fooplus() { init(); //foo::init(); bar(); //fooplus::bar(); }

      1 Reply Last reply
      0
      • A Alex Griffing

        The wrong function is getting called. I believe it goes like this: class foo { public: inline foo() { bar(); } virtual bar(); }; class fooplus : public foo { public: inline fooplus() : foo() {}; virtual bar(); } The problem is that when I instantiate fooplus, foo::bar gets called instead of fooplus::bar. I believe that if you said fooplus fooinst; fooinst.bar(); then it would call foo::bar and then fooplus::bar. I'm trying to use more of the power of C++, but stuff like this is making me want to just use it like C with member functions like I used to. :(

        B Offline
        B Offline
        Ben Burnett
        wrote on last edited by
        #3

        You should never call virtual functions within a ctor, the result is undefined. -Ben --------- On the topic of code with no error handling -- It's not poor coding, it's "optimistic" ;)

        A 1 Reply Last reply
        0
        • B Ben Burnett

          You should never call virtual functions within a ctor, the result is undefined. -Ben --------- On the topic of code with no error handling -- It's not poor coding, it's "optimistic" ;)

          A Offline
          A Offline
          Alex Griffing
          wrote on last edited by
          #4

          Is the alternative to say: pMyThing = new Thing(); pMyThing->Init(); all the time? That would suck.

          S L 2 Replies Last reply
          0
          • A Alex Griffing

            Is the alternative to say: pMyThing = new Thing(); pMyThing->Init(); all the time? That would suck.

            S Offline
            S Offline
            Stan Shannon
            wrote on last edited by
            #5

            Well, first off, polymophism is NOT the answer to every programming problem you might confront. So maybe for whatever it is you are trying to achieve you SHOULD be using C functions. I have no idea why you are defining your contstructors as inline, or what effect it has on the virtual calls. I've never seen that done before, and have no clue why you would need it. However, consider that the virtual table does not exist prior to the construction of the object. How would you expect a virtual call from the constructor to work? Obviously, as stated, it is undefined. You do not need to call an "Init" function after the ctor, because the object should initialize itself IN the ctor. Each derived class, will probably have unique initialization demands which do not warrent a virtual call anyway. If I really needed a "virtual constructor" (re: Stroustrup)which is essentially what you are trying to achieve here I would do something like this: class foo { foo(); //default constructor. foo( foo& rfoo ); // copy constructor. virtual foo* Clone(){ return( new foo( *this )); } virtual bar(); }; class fooplus : public foo { fooplus(); fooplus( fooplus& rfooplus ); virtual fooplus* Clone(){ return( new fooplus( *this )); } virtual bar(); }; In this way, an object can always return a properly initialized copy of itself on demand.

            A 1 Reply Last reply
            0
            • S Stan Shannon

              Well, first off, polymophism is NOT the answer to every programming problem you might confront. So maybe for whatever it is you are trying to achieve you SHOULD be using C functions. I have no idea why you are defining your contstructors as inline, or what effect it has on the virtual calls. I've never seen that done before, and have no clue why you would need it. However, consider that the virtual table does not exist prior to the construction of the object. How would you expect a virtual call from the constructor to work? Obviously, as stated, it is undefined. You do not need to call an "Init" function after the ctor, because the object should initialize itself IN the ctor. Each derived class, will probably have unique initialization demands which do not warrent a virtual call anyway. If I really needed a "virtual constructor" (re: Stroustrup)which is essentially what you are trying to achieve here I would do something like this: class foo { foo(); //default constructor. foo( foo& rfoo ); // copy constructor. virtual foo* Clone(){ return( new foo( *this )); } virtual bar(); }; class fooplus : public foo { fooplus(); fooplus( fooplus& rfooplus ); virtual fooplus* Clone(){ return( new fooplus( *this )); } virtual bar(); }; In this way, an object can always return a properly initialized copy of itself on demand.

              A Offline
              A Offline
              Alex Griffing
              wrote on last edited by
              #6

              Thanks for your reply! I don't think I've gone polymorphism happy (in the everything-looking-like-a-nail sense.) My vision is to have code that says: pObject = new MyFoobarizedZonkObject(); and I want the initialisation of the foobarized part of it to take place as a virtual function because there might also be a MyFoobarizedBlipObject whose foobarized part might be initialized a bit differently from MyFoobarizedZonkObject's. I guess you could take all the code that makes the objects foobarized and put it into its own class and use containment rather than inheritance, but this might or might not be natural. Does this make sense? I don't know what I was thinking with the inline constructor except that I've just started using inline functions a lot and I'm used to putting 'inline' whenever I don't have the function defined in the cpp file. I know this isn't how it goes though and that 'inline' shouldn't be before the constructor declaration. Saying 'virtual' before the 'bar' declaration in the fooplus class is also redundant, right? I guess I don't quite see how the 'virtual constructor' would apply because I don't have a correctly initialized object to start with. What would the code look like to use it? Thank you, Alex

              S 1 Reply Last reply
              0
              • A Alex Griffing

                Thanks for your reply! I don't think I've gone polymorphism happy (in the everything-looking-like-a-nail sense.) My vision is to have code that says: pObject = new MyFoobarizedZonkObject(); and I want the initialisation of the foobarized part of it to take place as a virtual function because there might also be a MyFoobarizedBlipObject whose foobarized part might be initialized a bit differently from MyFoobarizedZonkObject's. I guess you could take all the code that makes the objects foobarized and put it into its own class and use containment rather than inheritance, but this might or might not be natural. Does this make sense? I don't know what I was thinking with the inline constructor except that I've just started using inline functions a lot and I'm used to putting 'inline' whenever I don't have the function defined in the cpp file. I know this isn't how it goes though and that 'inline' shouldn't be before the constructor declaration. Saying 'virtual' before the 'bar' declaration in the fooplus class is also redundant, right? I guess I don't quite see how the 'virtual constructor' would apply because I don't have a correctly initialized object to start with. What would the code look like to use it? Thank you, Alex

                S Offline
                S Offline
                Stan Shannon
                wrote on last edited by
                #7

                The entire point of construction is to give an object the opportunity to uniquely initialize itself. Usually the way it is done is something like this: class foo1 { foo1() { m_x = 0; m_y = 0; m_y = 0; } }; class foo2 : public foo1 { // call the base class' constructor as you construct the derived class. foo2(): foo1() { m_xx = 0; m_yy = 0; mm_zz = 0; } }; class anotherfoo : public foo1 { anotherfoo (): foo1() { m_xx = 0; m_yy = 0; mm_zz = 0; } }; Now, both base and derived classs are properly initialize when you declare a foo2: foouser::UseFoo() { foo2 footoo; anotherfoo fooalso; // or foo2* pfootoo = new foo2(); anotherfoo* pfooalso = new anotherfoo(); }; So, I guess I don't really see what your issue is with initializing the objects. At this point, polymorphism has not even become an issue. The "Virtual Constructor" is simply a way to ensure a correct object is created if you do something like this: (As I typically keep my objects in paramatarized lists, this technique comes in handy) foouser::UseFoo() { foo2 footoo; DoSomethingElse( &footoo ); } foouser::DoSomethingElse( foo* pfoo ) { foo* pfooX = pfoo->Clone();// pfoo creates a copy of a foo2, or anotherfoo, if it was called with that. //// use pfooX. //// Obviously, for this example, I could have just used pfoo as is, but say I wanted to store a foo2 in its //// current state for whatever reason, this is very convenient. The point is that my Constructor is now capable of //// polymorphic behavior. delete pfooX; }; I believe you are technically right about the derived virtual bar() being redundant. But the rule of thumb, I think, is once virutal, always virtual. You can keep yourself out of a lot of trouble by keeping that in mind.

                1 Reply Last reply
                0
                • A Alex Griffing

                  Is the alternative to say: pMyThing = new Thing(); pMyThing->Init(); all the time? That would suck.

                  L Offline
                  L Offline
                  Lost User
                  wrote on last edited by
                  #8

                  Yep, it sucks, but that's just the way it is.

                  1 Reply Last reply
                  0
                  • A Alex Griffing

                    The wrong function is getting called. I believe it goes like this: class foo { public: inline foo() { bar(); } virtual bar(); }; class fooplus : public foo { public: inline fooplus() : foo() {}; virtual bar(); } The problem is that when I instantiate fooplus, foo::bar gets called instead of fooplus::bar. I believe that if you said fooplus fooinst; fooinst.bar(); then it would call foo::bar and then fooplus::bar. I'm trying to use more of the power of C++, but stuff like this is making me want to just use it like C with member functions like I used to. :(

                    M Offline
                    M Offline
                    Malcolm McMahon
                    wrote on last edited by
                    #9

                    I've been caught out by this one in the past. What happens is that the object, although allocated enough space for a fooplus is first initialised as a foo object, then the foo constructor is called. At that point the foo virtual method table is in effect. Only once the foo constructor exits does the fooplus intialisation occur and the VMT switches to the one containing fooplus::bar. This behaviour is logical, fooplus::bar might refer to variables in fooplus that the foo constructor doesn't know to initialise. How you get arround it depends on details of what you're doing that we don't know. If you're really getting into polymorphic programming you'll often find the best solution is static factory routines which give you a uniform access to constructors e.g. class foo { protected: foo(...) { }; public: static foo *factory( ... ); virtual void bar(); }; class fooplus : public foo { protected: fooplus( ... ) : foo(plus) { } public: static foo *factory( ... ); virtual void bar; .. }; foo *foo::facory( ... ) { foo *f = new foo( ...); f->bar(); return f; } foo *fooplus::factory ( ...) { fooplus *f = new fooplus ( ...); f->bar; return f; } Because the factory methods are static and have the same signature you can store pointers to them in a table of variations on foo.

                    1 Reply Last reply
                    0
                    Reply
                    • Reply as topic
                    Log in to reply
                    • Oldest to Newest
                    • Newest to Oldest
                    • Most Votes


                    • Login

                    • Don't have an account? Register

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • World
                    • Users
                    • Groups