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. Overloading methods with identical content in lot of derived classes

Overloading methods with identical content in lot of derived classes

Scheduled Pinned Locked Moved C / C++ / MFC
18 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.
  • F Offline
    F Offline
    FriendOfAsherah
    wrote on last edited by
    #1

    Following problem: I have a base class "B" in which there are some methods M1(),M2... Mn().

    class B {
    public
    //... some other methods
    //
    virtual void M1();
    virtual void M2();
    // ...
    virtual void Mn();
    };

    now I have multiple derived classes:

    class Ca1 : public B { .... };
    class Ca2 : public B { .... };
    //...
    class Can : public B { .... };

    and again derived each from above

    class Cb1 : public Ca1 { .... };
    class Cb2 : public Ca2 { .... };
    //...
    class Cbn : public Can { .... };

    And at last another deriving step by

    class Cc1 : public Cb1 { .... };
    class Cc2 : public Cb2 { .... };
    //...
    class Ccn : public Cb3 { .... };

    Now the Question: each of the derived last classes will override the methods M1, M2, M3 ...Mn... with the same functional content!

    class Cc1 : public Cb1 {
    virtual void M1() { /* code m1 */ } override;
    virtual void M2() { /* code m2 */ } override;
    ...
    virtual void M3() { /* code m3 */ } override;
    };
    class Cc2 : public Cb2 {
    virtual void M1() { /* code m1 */ } override;
    virtual void M2() { /* code m2 */ } override;
    ...
    virtual void M3() { /* code m3 */ } override;
    };

    ... this identical with identical code m1, m2 ... forall classes derived Cc1, Cc2, ... Ccn! How to best avoid to copy this M1, ... Mn block for method overriding into each derived class? The existing code packed everthing into a macro and copied this into the classes like

    #define DRIVED_METHODS \
    virtual void M1 { /* code m1 */ } \

    and so on which results in horrible undebugable code! Using multiple inheritance does not work:

    class Cc1 : public Cb1, public CMpack
    {};
    class Mpack { void M1 {}; ... };

    The only idea was to "map" each method to a class that collects these common methods

    class Mcommon {
    virtual void m_M1() { };
    virtual void m_M2() {};
    // ... etc
    }

    class Cc1 : public Mcommon
    {
    virtual void M1() { Mcommon::m_M1() ; } override
    // ... M2 and so on
    };

    I know that there must be a mistake in the whole design but Im not allowed to change much because nobody knows why the anchestor did such a design and sideeffects on changing code may happen. Have searched the web but best solution I got is the "Mapping" parameters, return types in M1...Mn have been simplyfied to void, empty in the text above

    CPalliniC L 2 Replies Last reply
    0
    • F FriendOfAsherah

      Following problem: I have a base class "B" in which there are some methods M1(),M2... Mn().

      class B {
      public
      //... some other methods
      //
      virtual void M1();
      virtual void M2();
      // ...
      virtual void Mn();
      };

      now I have multiple derived classes:

      class Ca1 : public B { .... };
      class Ca2 : public B { .... };
      //...
      class Can : public B { .... };

      and again derived each from above

      class Cb1 : public Ca1 { .... };
      class Cb2 : public Ca2 { .... };
      //...
      class Cbn : public Can { .... };

      And at last another deriving step by

      class Cc1 : public Cb1 { .... };
      class Cc2 : public Cb2 { .... };
      //...
      class Ccn : public Cb3 { .... };

      Now the Question: each of the derived last classes will override the methods M1, M2, M3 ...Mn... with the same functional content!

      class Cc1 : public Cb1 {
      virtual void M1() { /* code m1 */ } override;
      virtual void M2() { /* code m2 */ } override;
      ...
      virtual void M3() { /* code m3 */ } override;
      };
      class Cc2 : public Cb2 {
      virtual void M1() { /* code m1 */ } override;
      virtual void M2() { /* code m2 */ } override;
      ...
      virtual void M3() { /* code m3 */ } override;
      };

      ... this identical with identical code m1, m2 ... forall classes derived Cc1, Cc2, ... Ccn! How to best avoid to copy this M1, ... Mn block for method overriding into each derived class? The existing code packed everthing into a macro and copied this into the classes like

      #define DRIVED_METHODS \
      virtual void M1 { /* code m1 */ } \

      and so on which results in horrible undebugable code! Using multiple inheritance does not work:

      class Cc1 : public Cb1, public CMpack
      {};
      class Mpack { void M1 {}; ... };

      The only idea was to "map" each method to a class that collects these common methods

      class Mcommon {
      virtual void m_M1() { };
      virtual void m_M2() {};
      // ... etc
      }

      class Cc1 : public Mcommon
      {
      virtual void M1() { Mcommon::m_M1() ; } override
      // ... M2 and so on
      };

      I know that there must be a mistake in the whole design but Im not allowed to change much because nobody knows why the anchestor did such a design and sideeffects on changing code may happen. Have searched the web but best solution I got is the "Mapping" parameters, return types in M1...Mn have been simplyfied to void, empty in the text above

      CPalliniC Offline
      CPalliniC Offline
      CPallini
      wrote on last edited by
      #2

      Quote:

      each of the derived last classes will override the methods M1, M2, M3 ...Mn... with the same functional content!

      What's the purpose of that?

      In testa che avete, signor di Ceprano?

      F 2 Replies Last reply
      0
      • CPalliniC CPallini

        Quote:

        each of the derived last classes will override the methods M1, M2, M3 ...Mn... with the same functional content!

        What's the purpose of that?

        F Offline
        F Offline
        FriendOfAsherah
        wrote on last edited by
        #3

        some history I found out: they had a collection of B*

        typedef vector arrayB

        then they stored Ca1* ... Can* in such a collection later they stored Cc1* ... Ccn* in such a collection because all derived from B ...

        arrayB1 my_collection;
        my_collection.push_back(Cc1* ... ) //... etc

        this is valid because the Cc´s are derived from B B<--Cc1 , ... if it is a B* the B::M1() was called if it is a Ca1*, ...Can* the B::M1() was called if it is a Cb1*, ...Cbn* the B::M1() was called But if it is a Cc1*, ...Ccn* the overloaded Cc1::M1() etc. of the derived classes were called and do something different than the B::M1() I dont know further what its good for, but its the way it was it was implemented

        CPalliniC 1 Reply Last reply
        0
        • F FriendOfAsherah

          some history I found out: they had a collection of B*

          typedef vector arrayB

          then they stored Ca1* ... Can* in such a collection later they stored Cc1* ... Ccn* in such a collection because all derived from B ...

          arrayB1 my_collection;
          my_collection.push_back(Cc1* ... ) //... etc

          this is valid because the Cc´s are derived from B B<--Cc1 , ... if it is a B* the B::M1() was called if it is a Ca1*, ...Can* the B::M1() was called if it is a Cb1*, ...Cbn* the B::M1() was called But if it is a Cc1*, ...Ccn* the overloaded Cc1::M1() etc. of the derived classes were called and do something different than the B::M1() I dont know further what its good for, but its the way it was it was implemented

          CPalliniC Offline
          CPalliniC Offline
          CPallini
          wrote on last edited by
          #4

          OK, I misunderstood your original question. Could you possibly insert another derivation layer? Why the 'mapping' solution is not appealing?

          In testa che avete, signor di Ceprano?

          F 1 Reply Last reply
          0
          • CPalliniC CPallini

            OK, I misunderstood your original question. Could you possibly insert another derivation layer? Why the 'mapping' solution is not appealing?

            F Offline
            F Offline
            FriendOfAsherah
            wrote on last edited by
            #5

            Mapping means: to copy the same method mapping declaration to each class Cc1 ... Ccn so class Cc1: { ... list of M1() ...Mn()- mappings } class Cc2: { ... list of M1() ...Mn() mappings } .... class Ccn: { ... list of M1() ...Mn() mappings } this is lot of code ... isn´t there any way to say: class Cc1..n - overload "the punch of M1...Mn defined in a common set" layer in between does not work because: - Cc1...Ccn is derived from Cb1...Cbn - Cc_::M1() used some data of Cc_

            CPalliniC L 2 Replies Last reply
            0
            • F FriendOfAsherah

              Mapping means: to copy the same method mapping declaration to each class Cc1 ... Ccn so class Cc1: { ... list of M1() ...Mn()- mappings } class Cc2: { ... list of M1() ...Mn() mappings } .... class Ccn: { ... list of M1() ...Mn() mappings } this is lot of code ... isn´t there any way to say: class Cc1..n - overload "the punch of M1...Mn defined in a common set" layer in between does not work because: - Cc1...Ccn is derived from Cb1...Cbn - Cc_::M1() used some data of Cc_

              CPalliniC Offline
              CPalliniC Offline
              CPallini
              wrote on last edited by
              #6

              Quote:

              - Cc1...Ccn is derived from Cb1...Cbn - Cc_::M1() used some data of Cc_

              I don't get that. Either the methods are identical or not. If they are identical then they access variables with identical names.

              In testa che avete, signor di Ceprano?

              L F 2 Replies Last reply
              0
              • CPalliniC CPallini

                Quote:

                - Cc1...Ccn is derived from Cb1...Cbn - Cc_::M1() used some data of Cc_

                I don't get that. Either the methods are identical or not. If they are identical then they access variables with identical names.

                L Offline
                L Offline
                leon de boer
                wrote on last edited by
                #7

                The code in that form usually had a function to push/pull the class or object into and back off a stream. You would know the process if you are familiar with C# as serialization. Microsoft has provided a bit more support and safety doing in C++ with the DECLARE_SERIAL macro which I think is the macro you are talking about. Serialization: Making a Serializable Class[^] It's still pretty much done the same way. Just look into the code is the serialization still used?

                In vino veritas

                1 Reply Last reply
                0
                • F FriendOfAsherah

                  Mapping means: to copy the same method mapping declaration to each class Cc1 ... Ccn so class Cc1: { ... list of M1() ...Mn()- mappings } class Cc2: { ... list of M1() ...Mn() mappings } .... class Ccn: { ... list of M1() ...Mn() mappings } this is lot of code ... isn´t there any way to say: class Cc1..n - overload "the punch of M1...Mn defined in a common set" layer in between does not work because: - Cc1...Ccn is derived from Cb1...Cbn - Cc_::M1() used some data of Cc_

                  L Offline
                  L Offline
                  leon de boer
                  wrote on last edited by
                  #8

                  The code in that form usually had a function to push/pull the class or object into and back off a stream. You would know the process if you are familiar with C# as serialization. Microsoft has provided a bit more support and safety doing in C++ with MFC and the DECLARE_SERIAL macro which is the same as your MACRO. Serialization: Making a Serializable Class[^] It's still pretty much done the same way, you should have two constructors on the objects one of which has no parameters? Just look into the code and check if the serialization is still used?

                  In vino veritas

                  F 1 Reply Last reply
                  0
                  • CPalliniC CPallini

                    Quote:

                    - Cc1...Ccn is derived from Cb1...Cbn - Cc_::M1() used some data of Cc_

                    I don't get that. Either the methods are identical or not. If they are identical then they access variables with identical names.

                    F Offline
                    F Offline
                    FriendOfAsherah
                    wrote on last edited by
                    #9

                    sorry its tricky but: Cc1::M1() is identical to Cc2::M1() ... the only "data" some Mi() uses is the "this" pointer Cc1::M1() { code m1 } Cc2::M1() { code m1 } ... etc.. Cc1::M3() { f_calculate(this); ... } Cc2::M3() { f_calculate(this); ... } ...

                    CPalliniC 1 Reply Last reply
                    0
                    • L leon de boer

                      The code in that form usually had a function to push/pull the class or object into and back off a stream. You would know the process if you are familiar with C# as serialization. Microsoft has provided a bit more support and safety doing in C++ with MFC and the DECLARE_SERIAL macro which is the same as your MACRO. Serialization: Making a Serializable Class[^] It's still pretty much done the same way, you should have two constructors on the objects one of which has no parameters? Just look into the code and check if the serialization is still used?

                      In vino veritas

                      F Offline
                      F Offline
                      FriendOfAsherah
                      wrote on last edited by
                      #10

                      ?? stream? don´t understand because I don´t us a stream but do ou mean, that these horrible MFC macros came up because of th same problem?

                      L 1 Reply Last reply
                      0
                      • F FriendOfAsherah

                        sorry its tricky but: Cc1::M1() is identical to Cc2::M1() ... the only "data" some Mi() uses is the "this" pointer Cc1::M1() { code m1 } Cc2::M1() { code m1 } ... etc.. Cc1::M3() { f_calculate(this); ... } Cc2::M3() { f_calculate(this); ... } ...

                        CPalliniC Offline
                        CPalliniC Offline
                        CPallini
                        wrote on last edited by
                        #11

                        Since Cc1::M1 is identical to Cc2::M1, both Cc1 and Cc2 could inherit M1 from an intermediate class.

                        In testa che avete, signor di Ceprano?

                        F 1 Reply Last reply
                        0
                        • F FriendOfAsherah

                          ?? stream? don´t understand because I don´t us a stream but do ou mean, that these horrible MFC macros came up because of th same problem?

                          L Offline
                          L Offline
                          leon de boer
                          wrote on last edited by
                          #12

                          What is written looks very much like the way you do serialization in C++ Serialization - Wikipedia, the free encyclopedia[^] Read the article there are a number of reasons why you may want to serialize code from transmission thru, time based processing thru to encryption protection of code. You will note within the article they talk about C and C++ not having serialization but you can do it with a sort of standard form. Your code looks to me like that standard form. MFC has the same setup because it has serialized classes and even that is discussed in the wiki article. Note MFC's main reason for serialization: "The technique is called differential execution. It is useful in the programming of user interfaces whose contents are time-varying — graphical objects can be created, removed, altered, or made to handle input events without necessarily having to write separate code to do those things." You were saying you don't know why the original code was written like that and they won't let you change it. If you need the serialization it would indeed break the program if you write it a different way. So I am suggesting you check if the code is indeed doing serialization. If it is and that serialization is still needed you can not change it even if you wanted to.

                          In vino veritas

                          F 1 Reply Last reply
                          0
                          • CPalliniC CPallini

                            Since Cc1::M1 is identical to Cc2::M1, both Cc1 and Cc2 could inherit M1 from an intermediate class.

                            F Offline
                            F Offline
                            FriendOfAsherah
                            wrote on last edited by
                            #13

                            Problem is inheritance to base of Cc1 Cc2 etc B<-Ca1<-Cb1<-Cc1 B<-Ca2<-Cb3<-Cc2 if I use an intermediate class e.g D and declare D:M1() then following problem arises: class B { virtual M1() }; class Ca1 : public B class Cb1 : public Ca1 class D : { virtual M1() } ; class Cc1: public Cb1 , public D class Cc2 : public Cb2 , public D ... if I call now x->M1() with x is a Cc1* which method will be used? Does D::M1() overload B::M1(), what I like to have?

                            E 1 Reply Last reply
                            0
                            • L leon de boer

                              What is written looks very much like the way you do serialization in C++ Serialization - Wikipedia, the free encyclopedia[^] Read the article there are a number of reasons why you may want to serialize code from transmission thru, time based processing thru to encryption protection of code. You will note within the article they talk about C and C++ not having serialization but you can do it with a sort of standard form. Your code looks to me like that standard form. MFC has the same setup because it has serialized classes and even that is discussed in the wiki article. Note MFC's main reason for serialization: "The technique is called differential execution. It is useful in the programming of user interfaces whose contents are time-varying — graphical objects can be created, removed, altered, or made to handle input events without necessarily having to write separate code to do those things." You were saying you don't know why the original code was written like that and they won't let you change it. If you need the serialization it would indeed break the program if you write it a different way. So I am suggesting you check if the code is indeed doing serialization. If it is and that serialization is still needed you can not change it even if you wanted to.

                              In vino veritas

                              F Offline
                              F Offline
                              FriendOfAsherah
                              wrote on last edited by
                              #14

                              maybe I got now what you talk about "Changing the class is not possible when transfered via serial... because of reconstruction is dependent of class structure"? OK, this doesnt happen here, there is an extra struct that holds data to store and load. What I know is, that the code was extended within years, adding more and more features to the software. The derived classes have more features and do some different calculations e.g. B::M1() ... used in B, Ca1, Cb1 also Ca2, Cb2 ... ect is different to Cc1::M1(), Cc2::M1() ... etc.

                              1 Reply Last reply
                              0
                              • CPalliniC CPallini

                                Quote:

                                each of the derived last classes will override the methods M1, M2, M3 ...Mn... with the same functional content!

                                What's the purpose of that?

                                F Offline
                                F Offline
                                FriendOfAsherah
                                wrote on last edited by
                                #15

                                an example: We have animals, cats and dogs

                                class animal()
                                {
                                OpenMouth() ;
                                breath_in();
                                breath_out();
                                }
                                class cat() : public animal
                                {
                                play_with_wool();
                                }
                                class dog() : public animal
                                {
                                hunt_cats();
                                }
                                class mops1() : public dog
                                {
                                get_fat_and_fart()
                                }
                                class mops2() : public dog
                                {
                                get_fat()
                                }
                                class greyhound1() : public dog
                                {
                                run()
                                }
                                class specialdog() : public dog
                                {
                                run_fast()
                                }

                                now we want to extent _some_ dogs to know how to barf() for barf() we need some unctions of animal() (not all)

                                barf() { breath_in(); OpenMouth(); dosomething(); }

                                How can we add barf() to some (eg. 20 different dogs, and also some wolfs) without changing parent class structure?

                                class greyhound1() : public dog
                                {
                                run()
                                barf(); // added ...
                                }
                                class specialdog() : public dog
                                {
                                run_fast()
                                barf(); // added ...
                                }
                                class greywolf() : public wolf
                                {
                                barf(); // added
                                }

                                and next step: we have not only barf() we have 20 new extends for these aimals. It would mean: add these 20 functions to each animal seperately?

                                1 Reply Last reply
                                0
                                • F FriendOfAsherah

                                  Following problem: I have a base class "B" in which there are some methods M1(),M2... Mn().

                                  class B {
                                  public
                                  //... some other methods
                                  //
                                  virtual void M1();
                                  virtual void M2();
                                  // ...
                                  virtual void Mn();
                                  };

                                  now I have multiple derived classes:

                                  class Ca1 : public B { .... };
                                  class Ca2 : public B { .... };
                                  //...
                                  class Can : public B { .... };

                                  and again derived each from above

                                  class Cb1 : public Ca1 { .... };
                                  class Cb2 : public Ca2 { .... };
                                  //...
                                  class Cbn : public Can { .... };

                                  And at last another deriving step by

                                  class Cc1 : public Cb1 { .... };
                                  class Cc2 : public Cb2 { .... };
                                  //...
                                  class Ccn : public Cb3 { .... };

                                  Now the Question: each of the derived last classes will override the methods M1, M2, M3 ...Mn... with the same functional content!

                                  class Cc1 : public Cb1 {
                                  virtual void M1() { /* code m1 */ } override;
                                  virtual void M2() { /* code m2 */ } override;
                                  ...
                                  virtual void M3() { /* code m3 */ } override;
                                  };
                                  class Cc2 : public Cb2 {
                                  virtual void M1() { /* code m1 */ } override;
                                  virtual void M2() { /* code m2 */ } override;
                                  ...
                                  virtual void M3() { /* code m3 */ } override;
                                  };

                                  ... this identical with identical code m1, m2 ... forall classes derived Cc1, Cc2, ... Ccn! How to best avoid to copy this M1, ... Mn block for method overriding into each derived class? The existing code packed everthing into a macro and copied this into the classes like

                                  #define DRIVED_METHODS \
                                  virtual void M1 { /* code m1 */ } \

                                  and so on which results in horrible undebugable code! Using multiple inheritance does not work:

                                  class Cc1 : public Cb1, public CMpack
                                  {};
                                  class Mpack { void M1 {}; ... };

                                  The only idea was to "map" each method to a class that collects these common methods

                                  class Mcommon {
                                  virtual void m_M1() { };
                                  virtual void m_M2() {};
                                  // ... etc
                                  }

                                  class Cc1 : public Mcommon
                                  {
                                  virtual void M1() { Mcommon::m_M1() ; } override
                                  // ... M2 and so on
                                  };

                                  I know that there must be a mistake in the whole design but Im not allowed to change much because nobody knows why the anchestor did such a design and sideeffects on changing code may happen. Have searched the web but best solution I got is the "Mapping" parameters, return types in M1...Mn have been simplyfied to void, empty in the text above

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

                                  If I understood the question, the best method is using macro at header in derived classes and implementation in those cpp side (these must be different right?).

                                  F 1 Reply Last reply
                                  0
                                  • L Lost User

                                    If I understood the question, the best method is using macro at header in derived classes and implementation in those cpp side (these must be different right?).

                                    F Offline
                                    F Offline
                                    FriendOfAsherah
                                    wrote on last edited by
                                    #17

                                    yes, they are different or use one member in this functions that is diffrent. The functions to add itself are same to all, but refer to prior defined methods, functions or class members macros is the :wtf: WORST madhog (method) ever. I know this because im now in task to remove all these mass of macros (1 - 10 pages long) not debugable, now intllisense, you wont find anything. in addition the advantage of OOD /OOP has been destroyed with these macros because a lot of not used things were copied because the developer didn´t know whats in there anymore (stupid copying) Ther must be a smarter better way, hopefully

                                    1 Reply Last reply
                                    0
                                    • F FriendOfAsherah

                                      Problem is inheritance to base of Cc1 Cc2 etc B<-Ca1<-Cb1<-Cc1 B<-Ca2<-Cb3<-Cc2 if I use an intermediate class e.g D and declare D:M1() then following problem arises: class B { virtual M1() }; class Ca1 : public B class Cb1 : public Ca1 class D : { virtual M1() } ; class Cc1: public Cb1 , public D class Cc2 : public Cb2 , public D ... if I call now x->M1() with x is a Cc1* which method will be used? Does D::M1() overload B::M1(), what I like to have?

                                      E Offline
                                      E Offline
                                      ellegonzalez
                                      wrote on last edited by
                                      #18

                                      sorry its tricky but: Cc1::M1() is identical to Cc2::M1() ... the only "data" some Mi() uses is the "this" pointer Cc1::M1() { code m1 } Cc2::M1() { code m1 } ... etc.. Cc1::M3() { f_calculate(this); ... } Cc2::M3() { f_calculate(this); ... } ...

                                      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