Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Virtual base class and friend

95 views
Skip to first unread message

omveer

unread,
Feb 28, 2013, 3:02:06 AM2/28/13
to
Hi,

I'm trying below scenario:
class xx
{
xx(){}
friend class yy;
};

class yy: virtual public xx
{
public:
yy(){}
};

class zz:public yy
{
public:
};

Q1: It doesn't work with ZZ obj; Please help me understanding it.

class xx
{
xx(){}
friend class yy;
};

class yy: public xx
{
public:
yy(){}
};

class zz:public yy
{
public:
};

Q2: After removing virtual, it works for zz obj;. Why and how?

Thanks in advance.

Regards


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Thomas Richter

unread,
Feb 28, 2013, 7:08:39 AM2/28/13
to
Am 28.02.2013 09:02, schrieb omveer:
> Hi,
>
> I'm trying below scenario:
> class xx
> {
> xx(){}
> friend class yy;
> };
>
> class yy: virtual public xx
> {
> public:
> yy(){}
> };
>
> class zz:public yy
> {
> public:
> };
>
> Q1: It doesn't work with ZZ obj; Please help me understanding it.


Because, with the virtual in place, the every derived class (and thus
also zz in your code) and not only the next derived class needs to
construct the virtual bases (xx), and it cannot do that because the xx
constructor is private in zz. Without the virtual in place, the yy
constructor is responsible for constructing the xx object, and it can
do that because yy is a friend of xx.

Hence, with virtual in place, zz and yy are responsible for
constructing xx. Without it, only yy is.

So basically, what you have to understand is:

*) "friend" is not transitive. Just because a is a friend of b, and c
derives from a, doesn't make c a friend of b.

*) Construction of virtual base objects. These happen *not* in the
immediate superclasses, as it happens with regular inheritance, but in
every derived class.

Why is this so? Think about which problem virtual inheritance is
supposed to solve. (Hint, hint! The diamond shape, Hint, Hint!)

Greetings,
Thomas

Daniel Krügler

unread,
Feb 28, 2013, 7:11:30 AM2/28/13
to
On 2013-02-28 09:02, omveer wrote:
> Hi,
>
> I'm trying below scenario:
> class xx
> {
> xx(){}
> friend class yy;
> };
>
> class yy: virtual public xx
> {
> public:
> yy(){}
> };
>
> class zz:public yy
> {
> public:
> };
>
> Q1: It doesn't work with ZZ obj; Please help me understanding it.

In the future please always explain what you mean with "it doesn't
work". This description can mean anything or everything and I usually
don't reply to such fuzzy questions. I'm assuming in the following
that your problem is a compiler error when attempting to compile an
object declaration of the form

zz obj;

complaining along the lines of "default constructor of xx is not
accessible" or something similar.

In this case, both your questions are *related*. Virtual base classes
are very special, because they are initialized at a different time
compared to the normal way (C++ base classes and non-static members
are otherwise always initialized *before* the container class): They
are always initialized *first* by the most-derived class. This causes
a problem in your example, because it is *not* yy who is supposed to
invoke the (private) xx default constructor for an object of type zz,
but it is the type zz. Since you did not assign access rights to zz,
the implicit invocation is invalid.

A simple fix is to assign friendship to zz as well. Personally I would
stay away from such a design (virtual base class with private default
constructor), because it doesn't scale well: Your virtual base class
has to be aware of all derived classes - gulp! If you want to prevent
that user-code directly declares an object of type xx, you could
simply make the default constructor protected instead.

> class xx
> {
> xx(){}
> friend class yy;
> };
>
> class yy: public xx
> {
> public:
> yy(){}
> };
>
> class zz:public yy
> {
> public:
> };
>
> Q2: After removing virtual, it works for zz obj;. Why and how?

My description above explains it: In this case we have no virtual base
class, so yy is the type that will construct the xx base class. Thus,
the friendship to yy will ensure that this construction is valid.

HTH & Greetings from Bremen,

Daniel Kr�gler

omveer

unread,
Feb 28, 2013, 7:16:00 AM2/28/13
to
Thanks to Tobias M�ller. I got below response.

<omveer.c...@gmail.com> wrote:
> Hi,
>
> I'm trying below scenario:
> class xx
> {
> xx(){}
> friend class yy;
> };
>
> class yy: virtual public xx
> {
> public:
> yy(){}
> };
>
> class zz:public yy
> {
> public:
> };
>
> Q1: It doesn't work with ZZ obj; Please help me understanding it.

Your class zz implicitly has the following constructor:

class zz : public yy
{
public:
zz() : xx(), yy() {}
}

Constuctors of virtual base classes are called from every derived class
directly.

Consider the following case:

class A
{
public:
A();
A(int i);
};

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

class C : virtual public A
{
public:
C() : A(4) {}
};

class D : public B, public C
{
public:
// D() : B(), C() {} // -> Error, the A subobject
// is the same for B and C
// and can only be
// constructed once. But use
// A() or A(4)?
D() : A(), B(), C() {} // Correct
};

> class xx
> {
> xx(){}
> friend class yy;
> };
>
> class yy: public xx
> {
> public:
> yy(){}
> };
>
> class zz:public yy
> {
> public:
> };
>
> Q2: After removing virtual, it works for zz obj;. Why and how?
Your class zz implicitly has the following constructor:

class zz : public yy
{
public:
zz() : yy() {}
}

Constuctors of non-virtual base are only called from classes that inherit
directly.

Consider again the same case, but without virtual inheritance:

class A
{
public:
A();
A(int i);
};

class B : public A
{
public:
B() : A() {}
};

class C : public A
{
public:
C() : A(4) {}
};

class D : public B, public C
{
public:
D() : B(), C() {} // Correct: B and C have both
// their own A object and
// do the initialization on their own.
// D() : A(), B(), C() {} // Error
};

Seungbeom Kim

unread,
Mar 1, 2013, 3:17:11 AM3/1/13
to
On 2013-02-28 04:16, omveer wrote:
> Thanks to Tobias M�ller. I got below response.
>
[...]
>
> Consider the following case:
>
> class A
> {
> public:
> A();
> A(int i);
> };
>
> class B : virtual public A
> {
> public:
> B() : A() {}
> };
>
> class C : virtual public A
> {
> public:
> C() : A(4) {}
> };
>
> class D : public B, public C
> {
> public:
> // D() : B(), C() {} // -> Error, the A subobject
> // is the same for B and C
> // and can only be
> // constructed once. But use
> // A() or A(4)?

This is not an error, because it needs to construct A and the default
constructor of A is accessible from D. It doesn't matter how the c'tors
of B and C are defined to construct A; they are simply ignored.

> D() : A(), B(), C() {} // Correct

This is identical to the previous constructor (commented out).

> };

--
Seungbeom Kim

Tobias Müller

unread,
Mar 1, 2013, 12:57:42 PM3/1/13
to
Seungbeom Kim <musi...@bawi.org> wrote:
> On 2013-02-28 04:16, omveer wrote:
>> Thanks to Tobias Müller. I got below response.

That was in comp.lang.c++...

>> class D : public B, public C
>> {
>> public:
>> // D() : B(), C() {} // -> Error, the A subobject
>> // is the same for B and C
>> // and can only be
>> // constructed once. But use
>> // A() or A(4)?
>
> This is not an error, because it needs to construct A and the default
> constructor of A is accessible from D. It doesn't matter how the c'tors
> of B and C are defined to construct A; they are simply ignored.

Good catch, that was a bad example. But I think the OP still got the point.

Tobi


--
0 new messages