oo-problem

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Jan Boehme

    oo-problem

    Hi!
    Can anyone tell me why the output of this program is in both cases "from
    A!" an not "from B!" or "from C!" ?

    Thanks a lot for helping me,
    Jan.

    //CODE///////////////////////////////////////////////////////

    #include <iostream>
    using namespace std;

    class AImpl;
    class A
    {
    public:
    A();
    virtual ~A();
    const char * GetAddress();
    private:
    AImpl *pImpl;
    };

    class BImpl;
    class B : public A
    {
    public:
    B();
    virtual ~B();
    private:
    BImpl *pImpl;
    };

    class CImpl;
    class C : public A
    {
    public:
    C();
    virtual ~C();
    private:
    CImpl *pImpl;
    };

    class AImpl
    {
    public:
    char a[2000];
    AImpl()
    {
    strcpy(a, "from A!");
    };
    ~AImpl(){};
    const char * GetAddress()
    {
    return a;
    }
    };

    class BImpl : public AImpl
    {
    public:
    BImpl()
    {
    strcpy(a, "from B!");
    };
    ~BImpl(){};
    };

    class CImpl : public AImpl
    {
    public:
    CImpl()
    {
    strcpy(a, "from C!");
    };
    ~CImpl(){};
    };

    A::A()
    {
    pImpl = new AImpl();
    }

    const char * A::GetAddress()
    {
    return pImpl->GetAddress() ;
    }

    B::B()
    {
    pImpl = new BImpl();
    }

    C::C()
    {
    pImpl = new CImpl();
    }

    A::~A()
    {
    delete pImpl;
    }

    B::~B()
    {
    delete pImpl;
    }

    C::~C()
    {
    delete pImpl;
    }

    int main(int argc, char* argv[])
    {
    B m_xyz;
    cout << m_xyz.GetAddres s() << endl;
    C m_uvw;
    cout << m_xyz.GetAddres s() << endl;
    return 0;
    }

  • Hendrik Belitz

    #2
    Re: oo-problem

    Jan Boehme wrote:
    [color=blue]
    > Hi!
    > Can anyone tell me why the output of this program is in both cases "from
    > A!" an not "from B!" or "from C!" ?
    >
    > Thanks a lot for helping me,
    > Jan.
    >
    > //CODE///////////////////////////////////////////////////////
    >
    > #include <iostream>
    > using namespace std;
    >
    > class AImpl;
    > class A
    > {
    > public:
    > A();
    > virtual ~A();
    > const char * GetAddress();
    > private:
    > AImpl *pImpl;
    > };
    >
    > class BImpl;
    > class B : public A
    > {
    > public:
    > B();
    > virtual ~B();
    > private:
    > BImpl *pImpl;
    > };
    >
    > class CImpl;
    > class C : public A
    > {
    > public:
    > C();
    > virtual ~C();
    > private:
    > CImpl *pImpl;
    > };
    >
    > class AImpl
    > {
    > public:
    > char a[2000];
    > AImpl()
    > {
    > strcpy(a, "from A!");
    > };
    > ~AImpl(){};
    > const char * GetAddress()
    > {
    > return a;
    > }
    > };
    >
    > class BImpl : public AImpl
    > {
    > public:
    > BImpl()
    > {
    > strcpy(a, "from B!");
    > };
    > ~BImpl(){};
    > };
    >
    > class CImpl : public AImpl
    > {
    > public:
    > CImpl()
    > {
    > strcpy(a, "from C!");
    > };
    > ~CImpl(){};
    > };
    >
    > A::A()
    > {
    > pImpl = new AImpl();
    > }
    >
    > const char * A::GetAddress()
    > {
    > return pImpl->GetAddress() ;
    > }
    >
    > B::B()
    > {
    > pImpl = new BImpl();
    > }
    >
    > C::C()
    > {
    > pImpl = new CImpl();
    > }
    >
    > A::~A()
    > {
    > delete pImpl;
    > }
    >
    > B::~B()
    > {
    > delete pImpl;
    > }
    >
    > C::~C()
    > {
    > delete pImpl;
    > }
    >
    > int main(int argc, char* argv[])
    > {
    > B m_xyz;
    > cout << m_xyz.GetAddres s() << endl;
    > C m_uvw;
    > cout << m_xyz.GetAddres s() << endl;
    > return 0;
    > }[/color]

    You redefined pImpl in B and C. Since you dont overwrite your virtual method
    GetAddress() in B and C, only the implementation of A will be used. This
    will result in
    const char * A::GetAddress()
    {
    return A::pImpl->GetAddress() ;
    }
    ^-- !!!

    For the behavior you desire, you need to overwrite getAddress() in B and C.
    BTW, it's quite bad to create data members of the same name in base and
    derived classes. Avoiding this will also avoid your problem.

    --
    Dipl.-Inform. Hendrik Belitz
    Central Laboratory of Electronics
    Research Center Juelich

    Comment

    • Chris Theis

      #3
      Re: oo-problem


      "Jan Boehme" <aiscape@hotmai l.com> wrote in message
      news:br6nh8$293 ps7$1@ID-77850.news.uni-berlin.de...[color=blue]
      > Hi!
      > Can anyone tell me why the output of this program is in both cases "from
      > A!" an not "from B!" or "from C!" ?
      >
      > Thanks a lot for helping me,
      > Jan.
      >[/color]
      [SNIP]

      You have to keep in mind that inheriting class B from class A results in B
      having a part of A incorporated, which is what you normally want. Now you
      supply the GetAddress() function in class A only which operates on the
      implementation pointee of A! Thus calling this function from the derived
      class B (without overriding it!) it's perfectly okay that the operation is
      performed on the implementation pointee of A as this part is included in
      class B. What you have to do is to supply the same function also in class B
      operating on the pImpl pointer of B to get the behavior you expect. BTW it's
      not a very good practice to have variables of the same name in base &
      derived classes. This normally leads to confusion which you have already
      experienced. Some other remarks: the dtor of AImpl should be virtual as you
      derive from this class and don't forget to handle copy ctor & assignment in
      your A, B, C classes or the next problem will be waiting around the corner.

      HTH
      Chris



      Comment

      • Jan Boehme

        #4
        Re: oo-problem

        Hendrik Belitz schrieb:[color=blue]
        > You redefined pImpl in B and C. Since you dont overwrite your virtual method
        > GetAddress() in B and C, only the implementation of A will be used. This
        > will result in
        > const char * A::GetAddress()
        > {
        > return A::pImpl->GetAddress() ;
        > }
        > ^-- !!!
        >
        > For the behavior you desire, you need to overwrite getAddress() in B and C.
        > BTW, it's quite bad to create data members of the same name in base and
        > derived classes. Avoiding this will also avoid your problem.[/color]

        I partly understand your explanation und I know how to solve the problem.
        Alternatively I added a function to set the address-value a in the base
        class.
        Why this don't work?

        Thanks, Jan.

        #include <iostream>
        using namespace std;

        class AImpl;
        class A
        {
        public:
        A();
        virtual ~A();
        const char * GetAddress();
        void SetAddress(cons t char * par);
        private:
        AImpl *pImpl;
        };

        class BImpl;
        class B : public A
        {
        public:
        B();
        virtual ~B();
        private:
        BImpl *pImpl;
        };

        class CImpl;
        class C : public A
        {
        public:
        C();
        virtual ~C();
        private:
        CImpl *pImpl;
        };

        class AImpl
        {
        public:
        char a[2000];
        AImpl()
        {
        SetAddress("fro m A!");
        };
        ~AImpl(){};
        const char * GetAddress()
        {
        return a;
        }
        void SetAddress(cons t char * par)
        {
        strcpy(a, par);
        }
        };

        class BImpl : public AImpl
        {
        public:
        BImpl()
        {
        SetAddress("fro m B!");
        };
        ~BImpl(){};
        };

        class CImpl : public AImpl
        {
        public:
        CImpl()
        {
        SetAddress("fro m C!");
        };
        ~CImpl(){};
        };

        A::A()
        {
        pImpl = new AImpl();
        }

        const char * A::GetAddress()
        {
        return pImpl->GetAddress() ;
        }

        void A::SetAddress(c onst char * par)
        {
        pImpl->SetAddress(par );
        }

        B::B()
        {
        pImpl = new BImpl();
        }

        C::C()
        {
        pImpl = new CImpl();
        }

        A::~A()
        {
        delete pImpl;
        }

        B::~B()
        {
        delete pImpl;
        }

        C::~C()
        {
        delete pImpl;
        }

        int main(int argc, char* argv[])
        {
        B m_xyz;
        cout << m_xyz.GetAddres s() << endl;
        C m_uvw;
        cout << m_xyz.GetAddres s() << endl;
        return 0;
        }


        Comment

        • Jan Boehme

          #5
          Re: oo-problem

          Hi!

          Chris Theis schrieb:[color=blue]
          > You have to keep in mind that inheriting class B from class A results in B
          > having a part of A incorporated, which is what you normally want. Now you
          > supply the GetAddress() function in class A only which operates on the
          > implementation pointee of A! Thus calling this function from the derived
          > class B (without overriding it!) it's perfectly okay that the operation is
          > performed on the implementation pointee of A as this part is included in
          > class B. What you have to do is to supply the same function also in class B
          > operating on the pImpl pointer of B to get the behavior you expect. BTW it's
          > not a very good practice to have variables of the same name in base &
          > derived classes. This normally leads to confusion which you have already
          > experienced. Some other remarks: the dtor of AImpl should be virtual as you
          > derive from this class and don't forget to handle copy ctor & assignment in
          > your A, B, C classes or the next problem will be waiting around the corner.[/color]

          Thanks for your explanation. This is only a small snippet to focus to
          the main problem. I already thought the copy ctors & assignments are the
          problem and tried it out.
          But why it don't work by adding also a set-method to the base class and
          call in the c'tors of the derived classes. It should perform the
          operation at the implementation pointee of A?
          Thanks, Jan.

          Comment

          • Chris Theis

            #6
            Re: oo-problem


            "Jan Boehme" <aiscape@hotmai l.com> wrote in message
            news:br71gr$195 9$1@ID-77850.news.uni-berlin.de...[color=blue]
            > Hi!
            >[/color]
            [SNIP][color=blue]
            > Thanks for your explanation. This is only a small snippet to focus to
            > the main problem. I already thought the copy ctors & assignments are the
            > problem and tried it out.
            > But why it don't work by adding also a set-method to the base class and
            > call in the c'tors of the derived classes. It should perform the
            > operation at the implementation pointee of A?
            > Thanks, Jan.
            >[/color]

            Try the following in your code just for a test. Declare the pImpl member in
            class B public and add the following line to main:

            cout << m_xyz.pImpl->a << endl;
            cout << m_xyz.GetAddres s() << endl;

            What you'll get is that the line will deliver "from B" whereas the second
            statement will get you "from A". Thus you can see that the value for pImpl
            inside B has been set correctly, but calling GetAddress() obviously operates
            on the part of class A which is contained inside B, as already explained.

            HTH
            Chris


            Comment

            • Andreas Mueller

              #7
              Re: oo-problem

              Jan Boehme wrote:
              [color=blue]
              > Hendrik Belitz schrieb:[color=green]
              > > You redefined pImpl in B and C. Since you dont overwrite your
              > > virtual method GetAddress() in B and C, only the implementation of
              > > A will be used. This will result in
              > > const char * A::GetAddress()
              > > {
              > > return A::pImpl->GetAddress() ;
              > > }
              > > ^-- !!!
              > >
              > > For the behavior you desire, you need to overwrite getAddress() in
              > > B and C. BTW, it's quite bad to create data members of the same
              > > name in base and derived classes. Avoiding this will also avoid
              > > your problem.[/color]
              >
              > I partly understand your explanation und I know how to solve the
              > problem. Alternatively I added a function to set the address-value a
              > in the base class.
              > Why this don't work?[/color]

              [snip]
              [color=blue]
              >
              > int main(int argc, char* argv[])
              > {
              > B m_xyz;
              > cout << m_xyz.GetAddres s() << endl;
              > C m_uvw;[/color]

              Because you are printing m_xyz two times :-)
              [color=blue]
              > cout << m_xyz.GetAddres s() << endl; // <====[/color]

              //you probably meant:
              cout << m_uvw.GetAddres s() << endl;
              [color=blue]
              > return 0;
              > }
              >[/color]

              --
              To mail me directly, remove the NO*SPAM parts in
              NO*SPAMxmen40@g mx.netNO*SPAM

              Comment

              • Andreas Mueller

                #8
                Re: oo-problem

                Jan Boehme wrote:
                [color=blue]
                > Hi!
                > Can anyone tell me why the output of this program is in both cases
                > "from A!" an not "from B!" or "from C!" ?
                >
                > Thanks a lot for helping me,
                > Jan.
                >[/color]

                [snip]

                Hi,

                besides the solved problems with your first implementation, why are you
                redefining a pimpl pointer in each derived class? This means that A will
                carry around a AImpl, B an AImpl from A and a BImpl, and so on.

                As you derive your Implementation hiearchy paralell to the "interface"
                hiearchy, you can do it this way:

                #include <iostream>
                class AImpl;
                class A
                {
                public:
                A();
                virtual ~A();
                const char * GetAddress();
                protected://A does the imp handling for you
                void SetImp(AImpl* imp);
                private:
                AImpl *pImpl;
                };

                class BImpl;
                class B : public A
                {
                public:
                B();
                virtual ~B();
                };

                class CImpl;
                class C : public A
                {
                public:
                C();
                virtual ~C();
                };

                class AImpl
                {
                public:
                AImpl()
                {
                SetA("from A!");
                };
                virtual ~AImpl(){};//virtual dtor!!
                const char * GetAddress()
                {
                return a;
                }
                void SetA(const char* aa)
                {
                a = aa;
                }
                private:
                const char* a;
                };

                class BImpl : public AImpl
                {
                public:
                BImpl()
                {
                SetA("from B!");
                };
                virtual ~BImpl(){};
                };

                class CImpl : public AImpl
                {
                public:
                CImpl()
                {
                SetA("from C!");
                };
                virtual ~CImpl(){};
                };

                A::A()
                {// A uses AImpl
                SetImp(new AImpl());
                }
                void A::SetImp(AImpl * imp)
                {
                pImpl = imp;
                }
                const char * A::GetAddress()
                {
                return pImpl->GetAddress() ;
                }

                B::B()
                {//B uses BImpl, which is derived from AImpl
                SetImp(new BImpl());
                }

                C::C()
                {//C uses CImpl, which is indirectly derived from AImpl
                SetImp(new CImpl());
                }

                A::~A()
                {
                delete pImpl;
                }

                B::~B()
                {
                }

                C::~C()
                {
                }

                int main(int argc, char* argv[])
                {
                B m_xyz;
                std::cout << m_xyz.GetAddres s() << std::endl;
                C m_uvw;
                //You really meant this or is it a typo?
                //cout << m_xyz.GetAddres s() << endl;
                std::cout << m_uvw.GetAddres s() << std::endl;
                return 0;
                }

                HTH,
                Andy
                --
                To mail me directly, remove the NO*SPAM parts in
                NO*SPAMxmen40@g mx.netNO*SPAM

                Comment

                • Jan Boehme

                  #9
                  Re: oo-problem

                  Hi Andreas!

                  Andreas Mueller schrieb:[color=blue]
                  > As you derive your Implementation hiearchy paralell to the "interface"
                  > hiearchy, you can do it this way:[/color]
                  [color=blue]
                  > [snip][/color]
                  [color=blue]
                  > A::A()
                  > {// A uses AImpl
                  > SetImp(new AImpl());
                  > }
                  > void A::SetImp(AImpl * imp)
                  > {
                  > pImpl = imp;
                  > }
                  > const char * A::GetAddress()
                  > {
                  > return pImpl->GetAddress() ;
                  > }
                  >
                  > B::B()
                  > {//B uses BImpl, which is derived from AImpl
                  > SetImp(new BImpl());
                  > }
                  >
                  > C::C()
                  > {//C uses CImpl, which is indirectly derived from AImpl
                  > SetImp(new CImpl());
                  > }[/color]

                  Your solution looks just like the way I was looking for. I started to
                  break up this parallel inheritance and began to put all the stuff in one
                  Impl class and create only an outer class hierachie.
                  Thanks for helping me out here.
                  Jan.

                  PS: Yes, I meant m_xyz.GetAddres s() AND m_uvw.GetAddres s(). That was a typo.

                  Comment

                  Working...