converting derived class pointer to private base class pointer

S

subramanian100in

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
 
F

Francesco S. Carta

on said:
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.
 
S

subramanian100in

* "Francesco S. Carta said:
(e-mail address removed), India <[email protected]>, 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.

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
 
F

Francesco S. Carta

(e-mail address removed), India<[email protected]>, 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.
 
F

Francesco S. Carta

on said:
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.
 
G

gwowen

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?
 
J

James Kanze

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.
 
G

gwowen

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).
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,754
Messages
2,569,527
Members
44,997
Latest member
mileyka

Latest Threads

Top