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. Other Discussions
  3. Clever Code
  4. duplicated member variables in derived classes

duplicated member variables in derived classes

Scheduled Pinned Locked Moved Clever Code
c++debugginghelpquestion
22 Posts 11 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.
  • J jhwurmbach

    bolivar123 wrote:

    Use of CArray vs. using std::vector has nothing to do with the point I was trying to make.

    Granted, but is is my habit to object against CArray whenever I see its use.:rolleyes: It was created with the early MFCs. Out of dire need when the MS-C++ was so fundamentally broken as being incapable of compiling any STL. There is no need to use the afxtempl.h-collections in new software! You are right with

    for (int i=0;imyType)
    {
    case TYPEA:
    DoSomethingWithTypeA(pA);
    break;
    case TYPEB:
    DoSomethingWithTypeB((B*)ptr);
    break;
    case TYPEC:
    DoSomethingWithTypeC((C*)ptr);
    break;
    }
    }

    pA->myType will always be TYPEA (or undefined, with your unmodified code from the first posting). I had been misled by the debugger (VC2003), which is capable of showing the virtual variable (TYPEB, TYPEC) when the mouse is hovering over pA. When hovering over pA->myType, the correct value is shown, though. This whole issue is one of the confusing points of the C++ typesystem, but not a subtle bug, I think. You ordered a A*, so you got an A*.


    "We trained hard, but it seemed that every time we were beginning to form up into teams we would be reorganised. I was to learn later in life that we tend to meet any new situation by reorganising: and a wonderful method it can be for creating the illusion of progress, while producing confusion, inefficiency and demoralisation." -- Caius Petronius, Roman Consul, 66 A.D.

    B Offline
    B Offline
    bolivar123
    wrote on last edited by
    #7

    Previous versions of MFC had a CArray class and different variants CStringArray, CObArray, etc. not the CArray template.

    N 1 Reply Last reply
    0
    • C CPallini

      That is an issue, but it is also, I think, a bad design of the class hierarchy. :)

      If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.

      B Offline
      B Offline
      bolivar123
      wrote on last edited by
      #8

      This actually happened in one of our applications. We have a lot of code that has been ported and refactored from C to C++. So some of the classes we now have, were once C structs. In one case the myType member was duplicated. This is how I came across this little problem.

      C 1 Reply Last reply
      0
      • B bolivar123

        This actually happened in one of our applications. We have a lot of code that has been ported and refactored from C to C++. So some of the classes we now have, were once C structs. In one case the myType member was duplicated. This is how I came across this little problem.

        C Offline
        C Offline
        CPallini
        wrote on last edited by
        #9

        So you have to take into account a little re-design step in your refactoring process... :)

        If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.

        1 Reply Last reply
        0
        • B bolivar123

          Previous versions of MFC had a CArray class and different variants CStringArray, CObArray, etc. not the CArray template.

          N Offline
          N Offline
          Nemanja Trifunovic
          wrote on last edited by
          #10

          bolivar123 wrote:

          Previous versions of MFC had a CArray class and different variants CStringArray, CObArray, etc. not the CArray template.

          Even so, MFC collection classes are considered deprecated within MS VC++ team. See this thread[^]: The MFC collection classes are only there for backwards compatibility. C++ has a standard for collection classes and that is the Standards C++ Library. There is no technical drawback for using any of the standard library in an MFC application. We do not plan on making significant changes in this area. Ronald Laeremans Acting Product Unit Manager Vsual C++ Team


          Programming Blog utf8-cpp

          B 1 Reply Last reply
          0
          • N Nemanja Trifunovic

            bolivar123 wrote:

            Previous versions of MFC had a CArray class and different variants CStringArray, CObArray, etc. not the CArray template.

            Even so, MFC collection classes are considered deprecated within MS VC++ team. See this thread[^]: The MFC collection classes are only there for backwards compatibility. C++ has a standard for collection classes and that is the Standards C++ Library. There is no technical drawback for using any of the standard library in an MFC application. We do not plan on making significant changes in this area. Ronald Laeremans Acting Product Unit Manager Vsual C++ Team


            Programming Blog utf8-cpp

            B Offline
            B Offline
            bolivar123
            wrote on last edited by
            #11

            Oh goodie! If they don't plan on changing CArray, I'll continue using it. I just hate it when they go changing a good thing. Like the changes in CString from MFC 6 to MFC 7. Geez, I didn't think the original post would tangent to a debate on which is better......

            K 1 Reply Last reply
            0
            • J jhwurmbach

              bolivar123 wrote:

              Use of CArray vs. using std::vector has nothing to do with the point I was trying to make.

              Granted, but is is my habit to object against CArray whenever I see its use.:rolleyes: It was created with the early MFCs. Out of dire need when the MS-C++ was so fundamentally broken as being incapable of compiling any STL. There is no need to use the afxtempl.h-collections in new software! You are right with

              for (int i=0;imyType)
              {
              case TYPEA:
              DoSomethingWithTypeA(pA);
              break;
              case TYPEB:
              DoSomethingWithTypeB((B*)ptr);
              break;
              case TYPEC:
              DoSomethingWithTypeC((C*)ptr);
              break;
              }
              }

              pA->myType will always be TYPEA (or undefined, with your unmodified code from the first posting). I had been misled by the debugger (VC2003), which is capable of showing the virtual variable (TYPEB, TYPEC) when the mouse is hovering over pA. When hovering over pA->myType, the correct value is shown, though. This whole issue is one of the confusing points of the C++ typesystem, but not a subtle bug, I think. You ordered a A*, so you got an A*.


              "We trained hard, but it seemed that every time we were beginning to form up into teams we would be reorganised. I was to learn later in life that we tend to meet any new situation by reorganising: and a wonderful method it can be for creating the illusion of progress, while producing confusion, inefficiency and demoralisation." -- Caius Petronius, Roman Consul, 66 A.D.

              Z Offline
              Z Offline
              Zac Howland
              wrote on last edited by
              #12

              jhwurmbach wrote:

              Out of dire need when the MS-C++ was so fundamentally broken as being incapable of compiling any STL.

              It was created because there was no STL at the time. STL wasn't standard until 1999, MFC's collection classes have been around since 1994.

              jhwurmbach wrote:

              There is no need to use the afxtempl.h-collections in new software!

              There is nothing fundamentally wrong with MFC's collection classes. They are perfectly fine, and unless you are actually making use of some of the more advanced features of STL, MFC's templates are even easier to use in some cases. You use the tool that fits you best for what you need to accomplish. To the OP, the biggest problem with the code is the member variables in the derived classes hiding the one in the base class. A better way to do this kind of thing is:

              class A
              {
              public:
              	A(int type) : _Type(type) {}
              	virtual ~A() {}
              
              	virtual int getType() = 0;
              };
              
              class B : public A
              {
              public:
              	B() {}
              	virtual ~B() {}
              
              	virtual int getType() { return TYPEB; }
              };
              
              class C : public A
              {
              public:
              	C() {}
              	virtual ~C() {}
              
              	virtual int getType() { return TYPEC; }
              };
              

              If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week Zac

              1 Reply Last reply
              0
              • J jhwurmbach

                bolivar123 wrote:

                Use of CArray vs. using std::vector has nothing to do with the point I was trying to make.

                Granted, but is is my habit to object against CArray whenever I see its use.:rolleyes: It was created with the early MFCs. Out of dire need when the MS-C++ was so fundamentally broken as being incapable of compiling any STL. There is no need to use the afxtempl.h-collections in new software! You are right with

                for (int i=0;imyType)
                {
                case TYPEA:
                DoSomethingWithTypeA(pA);
                break;
                case TYPEB:
                DoSomethingWithTypeB((B*)ptr);
                break;
                case TYPEC:
                DoSomethingWithTypeC((C*)ptr);
                break;
                }
                }

                pA->myType will always be TYPEA (or undefined, with your unmodified code from the first posting). I had been misled by the debugger (VC2003), which is capable of showing the virtual variable (TYPEB, TYPEC) when the mouse is hovering over pA. When hovering over pA->myType, the correct value is shown, though. This whole issue is one of the confusing points of the C++ typesystem, but not a subtle bug, I think. You ordered a A*, so you got an A*.


                "We trained hard, but it seemed that every time we were beginning to form up into teams we would be reorganised. I was to learn later in life that we tend to meet any new situation by reorganising: and a wonderful method it can be for creating the illusion of progress, while producing confusion, inefficiency and demoralisation." -- Caius Petronius, Roman Consul, 66 A.D.

                M Offline
                M Offline
                Mike ONeill
                wrote on last edited by
                #13

                jhwurmbach wrote:

                I had been misled by the debugger (VC2003), which is capable of showing the virtual variable (TYPEB, TYPEC) when the mouse is hovering over pA.

                What is a "virtual variable"? I don't think that there is any such beast. Mike

                J 1 Reply Last reply
                0
                • M Mike ONeill

                  jhwurmbach wrote:

                  I had been misled by the debugger (VC2003), which is capable of showing the virtual variable (TYPEB, TYPEC) when the mouse is hovering over pA.

                  What is a "virtual variable"? I don't think that there is any such beast. Mike

                  J Offline
                  J Offline
                  jhwurmbach
                  wrote on last edited by
                  #14

                  Mike O`Neill wrote:

                  What is a "virtual variable"? I don't think that there is any such beast.

                  No - there isn't. Thats the point of this example. But the debugger shows - when the mouse hovers over pA - the value TYPEB or TYPEC for the variable myType - which is undefined, as the experiment with the switch/case shows. .


                  "We trained hard, but it seemed that every time we were beginning to form up into teams we would be reorganised. I was to learn later in life that we tend to meet any new situation by reorganising: and a wonderful method it can be for creating the illusion of progress, while producing confusion, inefficiency and demoralisation." -- Caius Petronius, Roman Consul, 66 A.D.

                  1 Reply Last reply
                  0
                  • B bolivar123

                    Consider the following simple Win32 console app. It defines 3 classes A, B, and C. The classes B and C derive from class A. We create a CArray of class A pointers. Since B and C are derived from A, we can add pointers to B and C to the CArray. On the lines with "LINE A", "LINE B", and "LINE C" comments, what would the value of pA->myType be in each case? Hint, it won't be TYPEA, TYPEB, or TYPEC! To test this app, set breakpoints at each of the 3 lines with the calls to GetAt, and view the value of pA->myType in the debugger.

                    // FooTest.cpp : Defines the entry point for the console application.
                    //

                    #include "stdafx.h"
                    #include "FooTest.h"
                    #include <afxtempl.h>

                    #ifdef _DEBUG
                    #define new DEBUG_NEW
                    #endif

                    // The one and only application object

                    CWinApp theApp;

                    using namespace std;

                    enum TClassType {TYPEA, TYPEB, TYPEC};

                    class A
                    {
                    public:
                    A() {};
                    ~A();
                    TClassType myType;
                    };

                    class B : public A
                    {
                    public:
                    B() { myType = TYPEB; }
                    ~B();
                    TClassType myType;
                    };

                    class C : public A
                    {
                    public:
                    C() { myType = TYPEC; }
                    ~C();
                    TClassType myType;
                    };

                    int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
                    {
                    int nRetCode = 0;
                    CArray<A*> myArray;
                    A* pA;

                    myArray.Add(new A);
                    myArray.Add(new B);
                    myArray.Add(new C);
                     
                    pA = myArray.GetAt(0); //LINE A
                    pA = myArray.GetAt(1); //LINE B
                    pA = myArray.GetAt(2); //LINE C
                    
                    
                    // initialize MFC and print and error on failure
                    if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
                    {
                    	// TODO: change error code to suit your needs
                    	\_tprintf(\_T("Fatal Error: MFC initialization failed\\n"));
                    	nRetCode = 1;
                    }
                    else
                    {
                    	// TODO: code your application's behavior here.
                    }
                    
                    return nRetCode;
                    

                    }

                    P Offline
                    P Offline
                    Pierre Leclercq
                    wrote on last edited by
                    #15

                    <Not meaning to be mean> <But...> Well, not sure this belongs to subtle bugs. The repetition of the same variable names would push it to bad design. And the unitialized member variable in the base class pushes it to bad code. </...But> <Not even> Talking about the lack of virtual destructors in a class hierarchy. Or <Ksss...> The use of public member variable. </...Ksss> </Not even> </Not meaning to be mean> <Feels like...> X| </...Feels like>

                    B 1 Reply Last reply
                    0
                    • B bolivar123

                      Oh goodie! If they don't plan on changing CArray, I'll continue using it. I just hate it when they go changing a good thing. Like the changes in CString from MFC 6 to MFC 7. Geez, I didn't think the original post would tangent to a debate on which is better......

                      K Offline
                      K Offline
                      Kevin McFarlane
                      wrote on last edited by
                      #16

                      bolivar123 wrote:

                      I didn't think the original post would tangent to a debate on which is better.....

                      Yes, it shouldn't really have done this as, for example, even if STL is the recommended way you could quite validly have been maintaining legacy code. Nonetheless, as an aside, I agree with the other guys that, other things being equal, we should prefer the STL - certainly for new projects. It's not as though this stuff has only just come out. All experienced C++ developers should be comfortable enough with it by now. OTOH, I'm not that religious about it. For example, although I haven't done any MFC for ages, I did still prefer CString to string.

                      Kevin

                      1 Reply Last reply
                      0
                      • P Pierre Leclercq

                        <Not meaning to be mean> <But...> Well, not sure this belongs to subtle bugs. The repetition of the same variable names would push it to bad design. And the unitialized member variable in the base class pushes it to bad code. </...But> <Not even> Talking about the lack of virtual destructors in a class hierarchy. Or <Ksss...> The use of public member variable. </...Ksss> </Not even> </Not meaning to be mean> <Feels like...> X| </...Feels like>

                        B Offline
                        B Offline
                        bolivar123
                        wrote on last edited by
                        #17

                        It is bad design and/or bad code for new developed code, but if you're cleaning up/encapsulating somebody else's code (who is no longer with the company)... BTW, does the incorrect use of XML tags make your post bad code?

                        P P 2 Replies Last reply
                        0
                        • B bolivar123

                          It is bad design and/or bad code for new developed code, but if you're cleaning up/encapsulating somebody else's code (who is no longer with the company)... BTW, does the incorrect use of XML tags make your post bad code?

                          P Offline
                          P Offline
                          PIEBALDconsult
                          wrote on last edited by
                          #18

                          I expect those will soon be Microsoft extensions to XML.

                          B P 2 Replies Last reply
                          0
                          • P PIEBALDconsult

                            I expect those will soon be Microsoft extensions to XML.

                            B Offline
                            B Offline
                            bolivar123
                            wrote on last edited by
                            #19

                            Until then, it'll be a not so subtle bug :laugh:

                            1 Reply Last reply
                            0
                            • B bolivar123

                              It is bad design and/or bad code for new developed code, but if you're cleaning up/encapsulating somebody else's code (who is no longer with the company)... BTW, does the incorrect use of XML tags make your post bad code?

                              P Offline
                              P Offline
                              Pierre Leclercq
                              wrote on last edited by
                              #20

                              bolivar123 wrote:

                              incorrect use of XML tags

                              Are you talking about the "..."? That was done on purpose... But I'm sure you'll gladly encapsulate it into a new post :)

                              1 Reply Last reply
                              0
                              • P PIEBALDconsult

                                I expect those will soon be Microsoft extensions to XML.

                                P Offline
                                P Offline
                                Pierre Leclercq
                                wrote on last edited by
                                #21

                                Actually this is not XML, this an extension to plain English. :)

                                1 Reply Last reply
                                0
                                • B bolivar123

                                  Consider the following simple Win32 console app. It defines 3 classes A, B, and C. The classes B and C derive from class A. We create a CArray of class A pointers. Since B and C are derived from A, we can add pointers to B and C to the CArray. On the lines with "LINE A", "LINE B", and "LINE C" comments, what would the value of pA->myType be in each case? Hint, it won't be TYPEA, TYPEB, or TYPEC! To test this app, set breakpoints at each of the 3 lines with the calls to GetAt, and view the value of pA->myType in the debugger.

                                  // FooTest.cpp : Defines the entry point for the console application.
                                  //

                                  #include "stdafx.h"
                                  #include "FooTest.h"
                                  #include <afxtempl.h>

                                  #ifdef _DEBUG
                                  #define new DEBUG_NEW
                                  #endif

                                  // The one and only application object

                                  CWinApp theApp;

                                  using namespace std;

                                  enum TClassType {TYPEA, TYPEB, TYPEC};

                                  class A
                                  {
                                  public:
                                  A() {};
                                  ~A();
                                  TClassType myType;
                                  };

                                  class B : public A
                                  {
                                  public:
                                  B() { myType = TYPEB; }
                                  ~B();
                                  TClassType myType;
                                  };

                                  class C : public A
                                  {
                                  public:
                                  C() { myType = TYPEC; }
                                  ~C();
                                  TClassType myType;
                                  };

                                  int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
                                  {
                                  int nRetCode = 0;
                                  CArray<A*> myArray;
                                  A* pA;

                                  myArray.Add(new A);
                                  myArray.Add(new B);
                                  myArray.Add(new C);
                                   
                                  pA = myArray.GetAt(0); //LINE A
                                  pA = myArray.GetAt(1); //LINE B
                                  pA = myArray.GetAt(2); //LINE C
                                  
                                  
                                  // initialize MFC and print and error on failure
                                  if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
                                  {
                                  	// TODO: change error code to suit your needs
                                  	\_tprintf(\_T("Fatal Error: MFC initialization failed\\n"));
                                  	nRetCode = 1;
                                  }
                                  else
                                  {
                                  	// TODO: code your application's behavior here.
                                  }
                                  
                                  return nRetCode;
                                  

                                  }

                                  B Offline
                                  B Offline
                                  Bernodus Kristinsson
                                  wrote on last edited by
                                  #22

                                  The value-of pA->myType is the value-of pA->A::myType which has not been initialized. Some changes: class A {public: A(){/*myType = TYPEA;*/} ~A(){} TClassType myType;}; class B : public A {public: B(){ myType = TYPEB; } ~B(){} TClassType myType;}; class C : public A {public: C(){ myType = TYPEC; } ~C(){} int myType;}; A* pA; B* pB; C* pC; pA = myArray.GetAt(0); //LINE A pA = myArray.GetAt(1); //LINE B pB = (B*)pA; TClassType eAB = pB->myType; TClassType eAA = pB->A::myType; pA = myArray.GetAt(2); //LINE C pC = (C*)pA; TClassType eAC = TClassType)pC->myType; eAA = pC->A::myType; Results: TYPEB == pB->myType // B::myType 2 == pC->myType // C::myType, 2==TYPEC ? == pA->myType // A::myType when uninitialized TYPEA == pA->myType // A::myType when initializion is uncommented Comments: Data-members are hidden or overridden. "Plain" function-members are hidden or overridden. Virtual function-members are virtual (behavior you expected). Hiding/overriding depends on NAME not type (see TClassType versus int). More comments: Such hiding is probably most often not done on purpose. Therefore Hiding data-members is 99.9999% (sure to result in) a bug. Hiding function-members is 99% a bug.

                                  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