converting derived class pointer to private base class pointer

Discussion in 'C++' started by subramanian100in@yahoo.com, India, Aug 14, 2010.

  1. , India

    , India Guest

    Two days back, I have posted a question to comp.lang.c++ with the
    subject line "derived class and virtual function".
    In one of the replies to that question Francesco S. Carta had given
    the following program:

    #include <iostream>

    using namespace std;

    class Base {
    public:
    Base(int data = 0) : data(data) {};
    Base(const Base& base) : data(base.data) {};
    virtual Base* Clone() const {
    cout << "cloning Base" << endl;
    return new Base(*this);
    }
    int Data() const {
    return data;
    }
    private:
    int data;

    };

    class Derived : private Base {
    public:
    Derived(int data = 0) : Base(data) {};
    Derived(const Derived& derived) : Base(derived) {};
    Base* Clone() const {
    cout << "cloning Derived" << endl;
    return new Derived(*this);
    }

    };

    int main() {

    // fails, of course
    Base* pb = new Derived(42);

    Derived d(42);

    // calls Derived::Clone()
    Base* pb2 = d.Clone();

    // calls Derived::Clone()
    Base* pb3 = pb2->Clone();

    // prints 42
    cout << pb3->Data() << endl;

    }

    When I compiled this program with g++3.4.3 as
    g++ -std=c++98 -pedantic -Wall -Wextra a.cpp

    I get the following error:

    a.cpp: In function `int main()':
    a.cpp:35: error: `Base' is an inaccessible base of `Derived'
    a.cpp:35: warning: unused variable 'pb'

    This error corresponds to the line:
    Base* pb = new Derived(42);
    This is because since Base class is private, I am trying to convert
    'Derived*' to 'Base*'. However, in the Derived class Clone() function,
    I am returning 'new Derived(*this)' as 'Base*'.
    ie I am converting 'Derived*' to 'Base*'. How is this accepted in this
    function?
    Base* Clone() const {
    cout << "cloning Derived" << endl;
    return new Derived(*this);
    }

    Kindly clarify.

    Thanks
    V.Subramanian
     
    , India, Aug 14, 2010
    #1
    1. Advertising

  2. , India <>, on
    14/08/2010 08:40:06, wrote:

    > Two days back, I have posted a question to comp.lang.c++ with the
    > subject line "derived class and virtual function".
    > In one of the replies to that question Francesco S. Carta had given
    > the following program:
    >
    > #include<iostream>
    >
    > using namespace std;
    >
    > class Base {
    > public:
    > Base(int data = 0) : data(data) {};
    > Base(const Base& base) : data(base.data) {};
    > virtual Base* Clone() const {
    > cout<< "cloning Base"<< endl;
    > return new Base(*this);
    > }
    > int Data() const {
    > return data;
    > }
    > private:
    > int data;
    >
    > };
    >
    > class Derived : private Base {
    > public:
    > Derived(int data = 0) : Base(data) {};
    > Derived(const Derived& derived) : Base(derived) {};
    > Base* Clone() const {
    > cout<< "cloning Derived"<< endl;
    > return new Derived(*this);
    > }
    >
    > };
    >
    > int main() {
    >
    > // fails, of course
    > Base* pb = new Derived(42);
    >
    > Derived d(42);
    >
    > // calls Derived::Clone()
    > Base* pb2 = d.Clone();
    >
    > // calls Derived::Clone()
    > Base* pb3 = pb2->Clone();
    >
    > // prints 42
    > cout<< pb3->Data()<< endl;
    >
    > }
    >
    > When I compiled this program with g++3.4.3 as
    > g++ -std=c++98 -pedantic -Wall -Wextra a.cpp
    >
    > I get the following error:
    >
    > a.cpp: In function `int main()':
    > a.cpp:35: error: `Base' is an inaccessible base of `Derived'
    > a.cpp:35: warning: unused variable 'pb'
    >
    > This error corresponds to the line:
    > Base* pb = new Derived(42);
    > This is because since Base class is private, I am trying to convert
    > 'Derived*' to 'Base*'. However, in the Derived class Clone() function,
    > I am returning 'new Derived(*this)' as 'Base*'.
    > ie I am converting 'Derived*' to 'Base*'. How is this accepted in this
    > function?
    > Base* Clone() const {
    > cout<< "cloning Derived"<< endl;
    > return new Derived(*this);
    > }


    The instantiation that you uncommented in main() fails because it has no
    special rights to access the private base of Derived - and in fact I
    wrote "fails, of course" there.

    On the contrary, Derived::Clone() is part of Derived and as such as
    direct access to all the private interface of Derived and can do the
    conversion. The fact that that pointer is getting returned from the
    function itself is another matter - once we have a Base*, we can pass it
    along regardless of its relation with Derived.

    In any case, as a self-improvement, Derived::Clone should be returning a
    Derived* and not a Base*, as I learned else-thread.

    --
    FSC - http://userscripts.org/scripts/show/59948
    http://fscode.altervista.org - http://sardinias.com
     
    Francesco S. Carta, Aug 14, 2010
    #2
    1. Advertising

  3. , India

    , India Guest

    * "Francesco S. Carta" <> wrote:
    > , India <>, on
    > 14/08/2010 08:40:06, wrote:
    > ...
    > In any case, as a self-improvement, Derived::Clone should be returning a
    > Derived* and not a Base*, as I learned else-thread.
    >
    > --
    > FSC


    Thanks very much for providing this additional information. Is the
    reason for Derived::Clone() to return only 'Derived*' instead of
    'Base*', the following:
    If the Derived::Clone() returned a 'Base*' and if Base had a mutator
    which modifies the 'Base::data', it would amount to modifying the
    private part of Derived object(returned by Derived::Clone()) through
    the 'Base*' because the derivation is private ?
    Here is the complete program which, of course, is a modification of
    your program:
    #include <cstdlib>
    #include <iostream>

    using namespace std;

    class Base
    {
    public:
    Base(int data = 0) : data(data) {};
    Base(const Base& base) : data(base.data) {};
    virtual Base* Clone() const {
    cout << "cloning Base" << endl;
    return new Base(*this);
    }
    int Data() const {
    return data;
    }
    void Data(int i); // newly added mutator
    virtual ~Base() { }
    private:
    int data;
    };

    inline void Base::Data(int i)
    {
    data = i;

    return;
    }

    class Derived : private Base {
    public:
    Derived(int data = 0) : Base(data) {};
    Derived(const Derived& derived) : Base(derived) {};
    Base* Clone() const {
    cout << "cloning Derived" << endl;
    return new Derived(*this);
    }
    virtual ~Derived() { }
    };

    int main()
    {
    Derived d(42);
    Base* pb = d.Clone();
    cout << pb->Data() << endl;
    pb->Data(100);
    cout << pb->Data() << endl;
    delete pb;
    pb = 0;

    return EXIT_SUCCESS;
    }

    This program compiles fine with g++3.4.3 and when run, produces the
    output:
    cloning Derived
    42
    100
    Here, note that the '100' is the value stored in the Base::data of the
    Base portion of the Derived object. But this should not happen because
    Base is derived with 'private'. Hence if Derived::Clone() returned a
    'Base*', then, even if we modified the Base::data of this newly
    constructed Base object returned by Derived::Clone(), through
    Base::Data(value), then it is not wrong because we would be modifying
    an independent Base object. Is this understanding of mine is correct ?
    Kindly clarify.

    Thanks
    V.Subramanian
     
    , India, Aug 17, 2010
    #3
  4. , India

    James Kanze Guest

    On Aug 14, 5:34 pm, "Francesco S. Carta" <> wrote:
    > , India <>, on


    [...]
    > In any case, as a self-improvement, Derived::Clone should be
    > returning a Derived* and not a Base*, as I learned
    > else-thread.


    How is that a self improvement? I'd recommend against it in
    most cases.

    --
    James Kanze
     
    James Kanze, Aug 17, 2010
    #4
  5. James Kanze <>, on 17/08/2010 03:22:21, wrote:

    > On Aug 14, 5:34 pm, "Francesco S. Carta"<> wrote:
    >> , India<>, on

    >
    > [...]
    >> In any case, as a self-improvement, Derived::Clone should be
    >> returning a Derived* and not a Base*, as I learned
    >> else-thread.

    >
    > How is that a self improvement? I'd recommend against it in
    > most cases.


    I badly expressed myself - notice that I wasn't even aware of the
    "covariant return" possibility. Now, after reading your replies
    else-thread, I discovered that returning a Base* instead allows Base to
    be a private base, which could come handy in some cases. In other cases,
    one could very well want to keep that base completely inaccessible,
    hence returning Derived* would be the thing to do, I suppose.

    --
    FSC - http://userscripts.org/scripts/show/59948
    http://fscode.altervista.org - http://sardinias.com
     
    Francesco S. Carta, Aug 17, 2010
    #5
  6. , India <>, on
    17/08/2010 00:37:30, wrote:

    > * "Francesco S. Carta"<> wrote:
    >> , India<>, on
    >> 14/08/2010 08:40:06, wrote:
    >> ...
    >> In any case, as a self-improvement, Derived::Clone should be returning a
    >> Derived* and not a Base*, as I learned else-thread.
    >>
    >> --
    >> FSC

    >
    > Thanks very much for providing this additional information. Is the
    > reason for Derived::Clone() to return only 'Derived*' instead of
    > 'Base*', the following:
    > If the Derived::Clone() returned a 'Base*' and if Base had a mutator
    > which modifies the 'Base::data', it would amount to modifying the
    > private part of Derived object(returned by Derived::Clone()) through
    > the 'Base*' because the derivation is private ?


    Yes, but for that matter, you would be modifying the private part of
    Base too, because that private member has a public setter in this case,
    read below.

    > Here is the complete program which, of course, is a modification of
    > your program:
    > #include<cstdlib>
    > #include<iostream>
    >
    > using namespace std;
    >
    > class Base
    > {
    > public:
    > Base(int data = 0) : data(data) {};
    > Base(const Base& base) : data(base.data) {};
    > virtual Base* Clone() const {
    > cout<< "cloning Base"<< endl;
    > return new Base(*this);
    > }
    > int Data() const {
    > return data;
    > }
    > void Data(int i); // newly added mutator
    > virtual ~Base() { }
    > private:
    > int data;
    > };
    >
    > inline void Base::Data(int i)
    > {
    > data = i;
    >
    > return;
    > }
    >
    > class Derived : private Base {
    > public:
    > Derived(int data = 0) : Base(data) {};
    > Derived(const Derived& derived) : Base(derived) {};
    > Base* Clone() const {
    > cout<< "cloning Derived"<< endl;
    > return new Derived(*this);
    > }
    > virtual ~Derived() { }
    > };
    >
    > int main()
    > {
    > Derived d(42);
    > Base* pb = d.Clone();
    > cout<< pb->Data()<< endl;
    > pb->Data(100);
    > cout<< pb->Data()<< endl;
    > delete pb;
    > pb = 0;
    >
    > return EXIT_SUCCESS;
    > }
    >
    > This program compiles fine with g++3.4.3 and when run, produces the
    > output:
    > cloning Derived
    > 42
    > 100
    > Here, note that the '100' is the value stored in the Base::data of the
    > Base portion of the Derived object. But this should not happen because
    > Base is derived with 'private'. Hence if Derived::Clone() returned a
    > 'Base*', then, even if we modified the Base::data of this newly
    > constructed Base object returned by Derived::Clone(), through
    > Base::Data(value), then it is not wrong because we would be modifying
    > an independent Base object. Is this understanding of mine is correct ?
    > Kindly clarify.


    Actually, you are modifying a different Base object because we have
    created a new Derived, so the original Derived is not under discussion,
    so to say.

    Let's put it in another way: once you "legally" get a pointer to the
    base object you are allowed to access its public part. The point seems
    to be exactly about what the derived class does. In this case, being
    Base private, the client code cannot convert a Derived* to a Base*, but
    Derived itself can give an option to return a Base*:

    Base* GetBase() {
    return this;
    }

    Here the conversion from Derived* to Base* is done by Derived::GetBase()
    which has full access to the private base, hence the conversion is legit.

    Hope this message, along with other messages from James Kanze in the
    other threads too, helps you understand the point with this stuff.

    --
    FSC - http://userscripts.org/scripts/show/59948
    http://fscode.altervista.org - http://sardinias.com
     
    Francesco S. Carta, Aug 17, 2010
    #6
  7. , India

    gwowen Guest

    On Aug 17, 11:22 am, James Kanze <> wrote:
    > How is that a self improvement?  I'd recommend against it in
    > most cases.


    Can you elucidate why?

    If I return a Base*, I can't do

    Derived d;
    Derived* dptr = d.clone();

    What do I gain?
     
    gwowen, Aug 17, 2010
    #7
  8. , India

    James Kanze Guest

    On Aug 17, 1:27 pm, gwowen <> wrote:
    > On Aug 17, 11:22 am, James Kanze <> wrote:


    > > How is that a self improvement? I'd recommend against it in
    > > most cases.


    > Can you elucidate why?


    > If I return a Base*, I can't do


    > Derived d;
    > Derived* dptr = d.clone();


    > What do I gain?


    The fact that you can't do Derived* dptr = d.clone() :).

    Seriously, in the special case of clone, the issue is debatable.
    But typically, if you have a Base, client code shouldn't use
    Derived, once it has the instance. Or else, Derived implements
    an extended interface. In which case, "clone" should conform to
    the Base class interface, and any additional functions should
    have different signatures from those of Base.

    As I said, clone could be an exception. But since it's virtual,
    it will usually be private, and only accessible from the Base
    class interface anyway.

    --
    James Kanze
     
    James Kanze, Aug 17, 2010
    #8
  9. , India

    gwowen Guest

    On Aug 17, 5:57 pm, James Kanze <> wrote:
    > As I said, clone could be an exception.  But since it's virtual,
    > it will usually be private, and only accessible from the Base
    > class interface anyway.


    I can see your point with public inheritance, but (on the exceedingly
    rare occasions) when I use private inheritance I'm not guaranteeing an
    "is a" relationship, and I'm not guaranteeing Liskov-type
    substitution. So I don't want to to let anyone when obtain a
    reference (or pointer) to the Base part (since private inheritance is
    essentially an implementation detail).
     
    gwowen, Aug 18, 2010
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Harrison
    Replies:
    0
    Views:
    509
    John Harrison
    Aug 6, 2003
  2. tirath
    Replies:
    3
    Views:
    734
    Ivan Vecerina
    Oct 12, 2003
  3. Kavya
    Replies:
    2
    Views:
    397
  4. Replies:
    1
    Views:
    425
    myork
    May 23, 2007
  5. Replies:
    1
    Views:
    412
    Victor Bazarov
    May 23, 2007
Loading...

Share This Page