Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. [Solved] Return instanced class in base class
Forum Updated to NodeBB v4.3 + New Features

[Solved] Return instanced class in base class

Scheduled Pinned Locked Moved General and Desktop
19 Posts 3 Posters 4.5k 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.
  • M Offline
    M Offline
    MuldeR
    wrote on last edited by
    #10

    Visitor-style solution:
    @class Vehicle
    {
    virtual void load(Database *db, const int &id) = 0;
    };

    class Car : public Vehicle
    {
    virtual void load(Database *db, const int &id)
    {
    db->load(this, id);
    }
    };

    class Bike : public Vehicle
    {
    virtual void load(Database *db, const int &id)
    {
    db->load(this, id);
    }
    };

    class Database
    {
    void lookup(Vehicle *vehicle, const int &id)
    {
    vehicle->load(this, id);
    }

    void load(Car *car, const int &id)
    {
    /load car from DB/
    }

    void load(Bike *car, const int &id)
    {
    /load bike from DB/
    }
    }

    int main()
    {
    Database db;
    Car *mercedes = new Car();
    db.lookup(mercedes, 42);
    }@

    Yes, there's still a load() function for each type in the Database class, but somewhere that code has to go unavoidably!

    My OpenSource software at: http://muldersoft.com/

    Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

    Go visit the coop: http://youtu.be/Jay...

    1 Reply Last reply
    0
    • Chris KawaC Offline
      Chris KawaC Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on last edited by
      #11

      You've lost me again :(
      Do you mean something like this?

      @
      class Vehicle {
      whatever someCommonDBStuff(int ID) { ... }
      };

      class Car1 : public Vehicle {
      static Car1 find(int ID)
      {
      auto foo = someCommonDBStuff(ID);
      return Car1();
      }
      };

      class Car2 : public Vehicle {
      static Car2 find(int ID)
      {
      auto foo = someCommonDBStuff(ID);
      return Car2();
      }
      };
      @

      Where does template fit here? I can't see it. Why do you put find in the base? From what I see you want it to return different types in derived classes. In that case Base class shouldn't know anything about derived and you can't overload find on just the return type.

      The example code Car::find<Car>(4); you gave is basically equivalent to:
      @
      class Vehicle {};

      class Car1 : public Vehicle {
      static Car1 findCar1(int ID) { ... }
      };

      class Car2 : public Vehicle {
      static Car2 findCar2(int ID) { ... }
      };
      @
      just without template syntax. You create unrelated methods in derived classes this way.

      1 Reply Last reply
      0
      • Chris KawaC Offline
        Chris KawaC Offline
        Chris Kawa
        Lifetime Qt Champion
        wrote on last edited by
        #12

        MuldeR - what's wrong with returning reference to local static object?
        If you call the function twice you will get two references to it. Nothing wrong or dangerous there.
        Returning a pointer is no different (single or multithreading wise).

        In C++11 There's even a 1-line thread-safe singleton pattern:
        @
        Singleton& getIt () { static Singleton s; return s; }
        //thread safe because of the C++11 "magic-statics" guarantee
        @

        1 Reply Last reply
        0
        • M Offline
          M Offline
          MuldeR
          wrote on last edited by
          #13

          [quote author="Chris Kawa" date="1399061766"]
          MuldeR - what's wrong with returning reference to local static object?[/quote]

          If you call the function repeatedly, you are getting another reference - to the very same statically allocated object! The same object which is now again loaded from the Database! Witch your code, this is not possible:

          @Base &car1 = find(42);
          Base &car2 = find(666);@

          Now car1 and car2 are pointing to the very same object, which has been loaded with the data for entry 666, while the previously loaded data for entry 42 is lost. Almost certainly not what the caller what have expected.

          Even worse, imagine there's another thread that also makes use of your Factory class. It certainly would end up in a mess...

          [quote author="Chris Kawa" date="1399061766"]Returning a pointer is no different (single or multithreading wise).[/quote]

          It is! Each call would be returning a pointer to a completely new object, allocated on the heap via new operator. So it's perfectly safe to call it repeatedly. It's even re-entrant, i.e. safe to use with multiple threads.

          My OpenSource software at: http://muldersoft.com/

          Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

          Go visit the coop: http://youtu.be/Jay...

          1 Reply Last reply
          0
          • M Offline
            M Offline
            Max13
            wrote on last edited by
            #14

            [quote author="MuldeR" date="1399061131"]Yes, there's still a load() function for each type in the Database class, but somewhere that code has to go unavoidably![/quote]

            This is close to what I want, but when I say I don't need to reimplement "load/find" in subclass, it's because the implementation would be a copy-paste of the base class one:

            @class Vehicle
            {
            public:
            static QVariantMap loadFromDb(QString table, int id); // To make it simple
            static CLASS find(int id) // Static or pointer, not important
            {
            QVariantMap data = Base::loadFromDb(CLASS::staticMetaObject.className(), id); // Way to get the table for i.e.
            return CLASS(data);
            }
            }

            class Car
            {
            public:
            static Car find(int id)
            {
            QVariantMap data = Car::loadFromDb(Car::staticMetaObject.className(), id);
            return Car(data);
            }
            }@

            Here is an example of what I think I get if I have to reimplement "find()" or make a conditional allocation. As we can see, for Car, Bike, Moto, ... The code inside "find()" will be exactly the same except for the types, that's why I was trying to find a way to reuse base class code without switch or many if/else.

            We all have started by asking questions. Then after some time, we can begin answering them.

            1 Reply Last reply
            0
            • Chris KawaC Offline
              Chris KawaC Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on last edited by
              #15

              [quote author="MuldeR" date="1399062117"]
              Yes, you are getting another reference - to the very same statically allocated object! The same object which is now again loaded from the Database! [/quote]

              My impression was that was the intent. OP never said returned object should be different depending on the content returned from DB. I read it as a function that looks something up in DB and then returns a type-related object. Name "find" doesn't really suggest construction of any object copies.

              But of course if it's actualy a "createInstanceBasedOnSmthn()" just named "find()" then you're 100% right. I don't seem to get what you guys are talking about here so I'll better leave it to you to hammer out. I need my coffee anyway :P

              EDIT: Ok, that last OP entry confirms you DO need a separate instance (because it puts retrieved data into the constructor)

              1 Reply Last reply
              0
              • M Offline
                M Offline
                MuldeR
                wrote on last edited by
                #16

                [quote author="Max13" date="1399062356"][quote author="MuldeR" date="1399061131"]Yes, there's still a load() function for each type in the Database class, but somewhere that code has to go unavoidably![/quote]

                This is close to what I want, but when I say I don't need to reimplement "load/find" in subclass, it's because the implementation would be a copy-paste of the base class one:[/quote]

                If the load() from DB code is the same (copy&paste) for each sub-class type anyway, where is the problem? Why not do this right away:

                @class Vehicle {...};
                class Car : public Vehicle {...};
                class Bike : public Vehicle {...};

                class Database
                {
                static load(Vehicle *vehicle, const int &id)
                {
                /Loading code here/
                }
                }

                main()
                {
                Car *car = new Car();
                Database::load(car, 42);

                Bike *bike = new Bike();
                Database::load(bike, 666);
                }@

                Yes, you now have to create an instance of the proper type before calling the load function. But that is no different with your Template approach, where you need to know the proper type of the loaded object just as well...

                My OpenSource software at: http://muldersoft.com/

                Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

                Go visit the coop: http://youtu.be/Jay...

                1 Reply Last reply
                0
                • M Offline
                  M Offline
                  Max13
                  wrote on last edited by
                  #17

                  [quote author="Chris Kawa" date="1399062679"]OP never said returned object should be different depending on the content returned from DB.[/quote]
                  You were half right, it's not depending on the content returned by the DB, the return will depend on the calling class of find() (find() would return an instance of the calling class).

                  MuldeR: This is a good way to do it, but in my current class tree, a database instance exists in BaseClass. So if I could return the object, it's better.
                  Honestly, I've already implemented this possibility this way:

                  @Car car = new Car();
                  car.fill(Database::get(car.metaObject()->className(), 42);@

                  But my needs are precisely a way to do it in one line, because I also have an "all()" method which returns a QList<CLASS> for example if I need all the registered cars.

                  EDIT: "This":http://stackoverflow.com/a/15777222/640164 is also a way to use template pattern without repeating the templated class

                  We all have started by asking questions. Then after some time, we can begin answering them.

                  1 Reply Last reply
                  0
                  • M Offline
                    M Offline
                    MuldeR
                    wrote on last edited by
                    #18

                    [quote author="Max13" date="1399063674"]But my needs are precisely a way to do it in one line[/quote]

                    If that really is the problem, you could use a macro like:
                    @#define LOAD_VEHICLE(TYPE, NAME, ID)
                    TYPE *NAME;
                    Database::load(NAME, ID);

                    main()
                    {
                    LOAD_VEHICLE(Car, myCar, 42)
                    LOAD_VEHICLE(Bike, myBike, 666)
                    }@

                    Or similarly with the Template-based approach:
                    @#define LOAD_VEHICLE(TYPE, NAME, ID)
                    TYPE *NAME = Database::load<TYPE>(ID);

                    main()
                    {
                    LOAD_VEHICLE(Car, myCar, 42);
                    LOAD_VEHICLE(Bike, myBike, 666);
                    }@

                    My OpenSource software at: http://muldersoft.com/

                    Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

                    Go visit the coop: http://youtu.be/Jay...

                    1 Reply Last reply
                    0
                    • M Offline
                      M Offline
                      Max13
                      wrote on last edited by
                      #19

                      Thank you for all your suggestions.

                      After thinking about it, I realized that it's a design problem.
                      I won't use a template model Factory, but as every model is constructed with QVariantMap, I just have to make find() and all() return QVariantMap and simply construct my models with it:

                      @class Model : public DatabaseInterface
                      {
                      public:
                      static QVariantMap find(const int id, const QString table);
                      };
                      class Car : public Model
                      {
                      public:
                      static Car find(const int id)
                      {
                      return Car(Model::find(42, "Car"));
                      }
                      };

                      int main()
                      {
                      Car mercedes(Car::find(42));
                      }@

                      Your answer are still interesting for similar cases, but for mine it's just a design error (because I will never need to construct multiple object). I'd rather make my DatabaseInterface return QSqlQueryModel and QSqlTableModel to use them in my views.

                      Thanks for your answers

                      We all have started by asking questions. Then after some time, we can begin answering them.

                      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