Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Special Interest Groups
  3. C++ Gurus
  4. Problem using overridden methods
QtWS25 Last Chance

Problem using overridden methods

Scheduled Pinned Locked Moved C++ Gurus
24 Posts 9 Posters 12.7k Views
  • 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.
  • P Offline
    P Offline
    Psycho_Path
    wrote on last edited by
    #1

    So I created a class and sub-classes that override the parent's class looking something like this

    @
    MyClass()
    {
    }

    void MyClass::doSomething()
    {
    cout << "MyClass::doSomething()";
    }
    @

    @
    MyCClass1() (inherits from MyClass in the header file)
    {
    }

    void MyCClass1::doSomething()
    {
    cout << "MyCClass1::doSomething()";
    }
    @

    @
    MyCClass2() (inherits from MyClass in the header file)
    {
    }

    void MyCClass2::doSomething()
    {
    cout << "MyCClass2::doSomething()";
    }
    @

    @
    void main(etc...)
    {
    vector<MyClass> storage;
    MyCClass1 mcc1();
    MyCClass2 mcc2();
    storage.push_back(mcc1);
    storage.push_back(mcc2);
    for (int i = 0; i < storage.size(); i++)
    {
    storage[i].doSomething();
    }
    }
    @

    How do i get the vector's call to doSomething() to use the child classes doSomething() methods instead of the parent classes method? I've tried using virtual classes, but then the vector can't call the method as it's virtual for any MyClass objects.

    Thanks in advance.

    1 Reply Last reply
    0
    • L Offline
      L Offline
      leon.anavi
      wrote on last edited by
      #2

      You can cast instances of MyCClass1 and MyCClass2 to MyCClass and then to call the method doSomething:

      @
      // type cast derived-to-base
      MyClass* pBase = dynamic_cast<MyClass*>(&storage[i]);
      pBase->doSomething();
      @

      http://anavi.org/

      1 Reply Last reply
      0
      • P Offline
        P Offline
        Psycho_Path
        wrote on last edited by
        #3

        It actually occurred to me a bit after making this post that that's what I'd probably have to do. Is there a simple way of knowing which of MyCClass1 or MyCClass2 each of the objects in storage is without having some reference variable in MyClass?

        1 Reply Last reply
        0
        • M Offline
          M Offline
          mlong
          wrote on last edited by
          #4

          Try to dynamic_cast to each of the known types. If it casts, it's that type. If you get a 0 back, then it's not.

          Software Engineer
          My views and opinions do not necessarily reflect those of anyone -- living or dead, real or fictional -- in this universe or any other similar multiverse node. Void where prohibited. Your mileage may vary. Caveat emptor.

          1 Reply Last reply
          0
          • P Offline
            P Offline
            Psycho_Path
            wrote on last edited by
            #5

            What do you mean get back a 0? if I do

            @
            MyCClass1* pBase = dynamic_cast<MyCClass1*>(&storage[i]);
            @

            then pBase will = 0?

            1 Reply Last reply
            0
            • L Offline
              L Offline
              leon.anavi
              wrote on last edited by
              #6

              [quote author="Psycho_Path" date="1331438598"]What do you mean get back a 0? if I do

              @
              MyCClass1* pBase = dynamic_cast<MyCClass1*>(&storage[i]);
              @

              then pBase will = 0?[/quote]

              Depends :) What tools do you use to build your source code?

              In general dynamic_cast returns a null pointer to indicate a failure. If dynamic_cast of references is not possible a bad_cast exception is thrown.

              But if you are using Microsoft Visual C++ 2005 or newer then 0 will be returned on failure and no exception will be thrown. Please check Microsoft documentation for details : http://msdn.microsoft.com/en-us/library/cby9kycs(v=vs.80).aspx

              http://anavi.org/

              1 Reply Last reply
              0
              • W Offline
                W Offline
                Wilk
                wrote on last edited by
                #7

                Hello
                Try this out
                @ void main(etc...)
                {
                vector<MyClass *> storage;
                MyCClass1 *mcc1 = new MyCClass1();
                MyCClass2 *mcc2 = new MyCClass2();
                storage.push_back(mcc1);
                storage.push_back(mcc2);
                for (int i = 0; i < storage.size(); i++)
                {
                storage[i] ->doSomething();
                }
                }
                @

                1 Reply Last reply
                0
                • W Offline
                  W Offline
                  whpp
                  wrote on last edited by
                  #8

                  Wilk's solution works, though be careful!

                  Any added functionality in your derived classes (MyCClass1 and MyCClass2) cannot be called this way and will have to be dynamically casted to their respective derived class pointers. Say you have a doMore() function in MyCClass1, but not in MyClass:

                  @storage[0]->doMore();@

                  The above will not work, whereas the below will:
                  @
                  dynamic_cast<MyCClass1 *>(storage[0])->doMore();
                  @

                  Edit: Don't forget to use operator delete() after those operator new()s

                  1 Reply Last reply
                  0
                  • B Offline
                    B Offline
                    broadpeak
                    wrote on last edited by
                    #9

                    Casting is unnecessary. Use the polymorphism. In the Base class the doSomething() should be virtual. All other will be solved by the C++ compiler.

                    1 Reply Last reply
                    0
                    • W Offline
                      W Offline
                      Wilk
                      wrote on last edited by
                      #10

                      [quote author="whpp" date="1331476875"]
                      Any added functionality in your derived classes (MyCClass1 and MyCClass2) cannot be called this way and will have to be dynamically casted to their respective derived class pointers.[/quote]
                      If you need such functionality, you'd better use a container of objects of derived classes (MyCClass1 and MyCClass2), not of base class (MyClass) or of pointers to objects of base class. If each of derived classes has additional functionality (doMore()) then you should add a virtual or a pure virtual method in your base class, as broadpeak said above.

                      1 Reply Last reply
                      0
                      • ZlatomirZ Offline
                        ZlatomirZ Offline
                        Zlatomir
                        wrote on last edited by
                        #11

                        Virtual or not virtual, cast or no cast - this code wont work polymorphic
                        @ vector<MyClass> storage;
                        MyCClass1 mcc1();
                        MyCClass2 mcc2();
                        storage.push_back(mcc1); //you slice your objects here storage has a copy of MyClass "part" of your objects
                        storage.push_back(mcc2);
                        for (int i = 0; i < storage.size(); i++)
                        {
                        storage[i].doSomething();
                        }@
                        For polymorphic call you need pointers or references (and since vector can't hold references you must use pointers):
                        @
                        vector<MyClass*> storage;
                        MyCClass1 mcc1();
                        MyCClass2 mcc2();
                        storage.push_back(&mcc1);
                        storage.push_back(&mcc2);
                        for (int i = 0; i < storage.size(); i++)
                        {
                        storage[i]->doSomething(); //add virtual in the MyClass declaration
                        }
                        @
                        //just remember that the pointers stored in storage will be invalid when the objects get out of scope
                        or if you allocate dynamically you must delete the allocated memory before vector gets out of scope or before you remove the pointers from vector.

                        https://forum.qt.io/category/41/romanian

                        1 Reply Last reply
                        1
                        • W Offline
                          W Offline
                          whpp
                          wrote on last edited by
                          #12

                          @Zlatomir: Yes, that's basically Wilk's implementation, only using the address of-operator instead of all pointers.

                          [quote author="Wilk" date="1331481313"][quote author="whpp" date="1331476875"]
                          Any added functionality in your derived classes (MyCClass1 and MyCClass2) cannot be called this way and will have to be dynamically casted to their respective derived class pointers.[/quote]
                          If you need such functionality, you'd better use a container of objects of derived classes (MyCClass1 and MyCClass2), not of base class (MyClass) or of pointers to objects of base class. If each of derived classes has additional functionality (doMore()) then you should add a virtual or a pure virtual method in your base class, as broadpeak said above.
                          [/quote]

                          Of course. That's a valid option, but that would change the semantics of the example at hand.

                          1 Reply Last reply
                          0
                          • ZlatomirZ Offline
                            ZlatomirZ Offline
                            Zlatomir
                            wrote on last edited by
                            #13

                            [quote author="whpp" date="1331487349"]@Zlatomir: Yes, that's basically Wilk's implementation, only using the address of-operator instead of all pointers...[/quote]
                            You miss the point of my post, i only posted the code because i missed Wilk’s code

                            So the point was that the objects are sliced at push_back and you can do whatever you want with the objects (or their addresses) in the vector<MyClass> the objects are only MyClass objects - not MyClass1 so there is no way you can do any of MyClass1 specific functionality.

                            [quote author="whpp" date="1331487349"]...Of course. That's a valid option, but that would change the semantics of the example at hand.
                            [/quote]
                            You can't solve this issue without changing the semantics, because it's a misuse of polymorphism, since as i said earlier you don't have any derived objects into the vector.

                            https://forum.qt.io/category/41/romanian

                            1 Reply Last reply
                            0
                            • P Offline
                              P Offline
                              Psycho_Path
                              wrote on last edited by
                              #14

                              I think casting seems to make the most sense here as in my actual code, the vector is filled in a different function than the function that iterates through the vector to call the function that both sub-classes have. I don't really see any other way of accessing the other methods in each of the sub-classes the other way either. For the record, I'm using Qt to develop this code.

                              1 Reply Last reply
                              0
                              • ZlatomirZ Offline
                                ZlatomirZ Offline
                                Zlatomir
                                wrote on last edited by
                                #15

                                As i said i my first post casting will fail (for vector<MyClass>) there is no way to use MyClass1 (or any other derived functionality) because that part of your objects is lost. (this cast: MyClass1* pBase = dynamic_cast<MyClass1*>(&storage[i]); will fail for storage of type vector<MyClass>)

                                To use the overridden functions from that vector you need to use pointers into the vector, than the overridden functionality will work correctly and also the casting (of-course to the correct pointer type).

                                //also since MyClass is designed as base class don't forget the virtual destructor (for the case you call delete on a MyClass* that has the address of a dynamically allocated MyClass1 object)

                                https://forum.qt.io/category/41/romanian

                                1 Reply Last reply
                                0
                                • P Offline
                                  P Offline
                                  Psycho_Path
                                  wrote on last edited by
                                  #16

                                  Heh, since my last post I've come to realize what you've said to be very much true, however, in my actual code, as the objects created are being made in a function that ends before the call to the function that doSomething() gets called in is ran, the objects get deleted and the pointers are pointing to null memory. Is there any way to cast without using pointers that will work? Or should I just come up with a completely different structure for my code to run that doesn't involve this polymorphism?

                                  Edit: Just realized what you pointed out in your previous post about the functionality being lost as the vector allocates memory of size MyClass and not either of the MyCClass classes. In any case, is there an easy solution here? Or do I just have to use 2 seperate vectors of type MyCClass1 and MyCClass2?

                                  1 Reply Last reply
                                  0
                                  • W Offline
                                    W Offline
                                    Wilk
                                    wrote on last edited by
                                    #17

                                    [quote author="Psycho_Path" date="1331568900"]Heh, since my last post I've come to realize what you've said to be very much true, however, in my actual code, as the objects created are being made in a function that ends before the call to the function that doSomething() gets called in is ran, the objects get deleted and the pointers are pointing to null memory. Is there any way to cast without using pointers that will work? Or should I just come up with a completely different structure for my code to run that doesn't involve this polymorphism?

                                    Edit: Just realized what you pointed out in your previous post about the functionality being lost as the vector allocates memory of size MyClass and not either of the MyCClass classes. In any case, is there an easy solution here? Or do I just have to use 2 seperate vectors of type MyCClass1 and MyCClass2?[/quote]
                                    I gave you solution in my first post:
                                    @ void main(etc...)
                                    {
                                    vector<MyClass *> storage;
                                    MyCClass1 *mcc1 = new MyCClass1();
                                    MyCClass2 *mcc2 = new MyCClass2();
                                    storage.push_back(mcc1);
                                    storage.push_back(mcc2);
                                    for (int i = 0; i < storage.size(); i++)
                                    {
                                    storage[i] ->doSomething();
                                    }
                                    }
                                    @

                                    As you can see, you create objects using operator new(), so the pointers won't become invalid after exiting the function, where thery were created. From other hand you have to make destructor of base class (MyClass) virtual and explicity delete every object, when you've done:
                                    @
                                    foreach (MyClass *element,
                                    storage) {
                                    delete element;
                                    }
                                    @

                                    That's the classical way of creating a polymorphic behaviour. For more information try to read Bjarne Stroustrup C++ Programming Language, The (3rd Edition).

                                    1 Reply Last reply
                                    0
                                    • P Offline
                                      P Offline
                                      Psycho_Path
                                      wrote on last edited by
                                      #18

                                      Thanks for your help and for re-posting what you'd already taken the time to post that I'd overlooked. Much appreciated.

                                      1 Reply Last reply
                                      0
                                      • B Offline
                                        B Offline
                                        broadpeak
                                        wrote on last edited by
                                        #19

                                        Yes, point at Wilk . Polymorphism (with pointers) can help.
                                        @
                                        #include <iostream>
                                        #include <vector>

                                        using namespace std;

                                        class MyClass
                                        {
                                        public:
                                        virtual void doSomething() const
                                        {
                                        cout << "MyClass::doSomething" << endl;
                                        }
                                        };

                                        class MyCClass1: public MyClass
                                        {
                                        public:
                                        void doSomething() const
                                        {
                                        cout << "MyClass1::doSomething" << endl;
                                        }
                                        };

                                        class MyCClass2: public MyClass
                                        {
                                        public:
                                        void doSomething() const
                                        {
                                        cout << "MyClass2::doSomething" << endl;
                                        }
                                        };

                                        /*
                                        void writeall(vector<MyClass*>& s)
                                        {

                                        for (int i = 0; i < s.size() ; i++)
                                        {
                                            s[i]->doSomething();
                                        }
                                        

                                        }
                                        */

                                        int main()
                                        {
                                        vector<MyClass*> storage;
                                        MyCClass1* mcc1 = new MyCClass1();
                                        MyCClass2* mcc2 = new MyCClass2();
                                        storage.push_back(mcc1);
                                        storage.push_back(mcc2);

                                        //writeall(storage);
                                        
                                        for (int i = 0; i < storage.size() ; i++)
                                        {
                                            storage[i]->doSomething();
                                        }
                                        
                                        return 0;
                                        

                                        }
                                        @

                                        1 Reply Last reply
                                        0
                                        • ZlatomirZ Offline
                                          ZlatomirZ Offline
                                          Zlatomir
                                          wrote on last edited by
                                          #20

                                          broadpeak you forgot the virtual destructor for MyClass and also you forgot to delete the dynamic allocated memory.

                                          https://forum.qt.io/category/41/romanian

                                          1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved