From: Paul Bibbings on
On Jun 2, 8:00 pm, Mark_Galeck <clcppm-pos...(a)this.is.invalid> wrote:
> Hello,
>
> how to write a non-default constructor for a class that inherits an
> indirect base class, with multiple intermediate classes that list the
> base as virtual? In the SSCCE below, the compiler complains "error:
> no matching function for call to �Base::Base()". Thank you,
>
> Mark
>
> class Base {
> public:
> Base(int) {
> }
>
> };
>
> class Intermediate0: public virtual Base {
> public:
> Intermediate0(int arg) :
> Base(arg) {
> }
>
> };
>
> class Intermediate1: public virtual Base {
> public:
> Intermediate1(int arg) :
> Base(arg) {
> }
>
> };
>
> class Derived: public Intermediate0, public Intermediate1 {
> public:
> Derived(int arg) :
> Intermediate0(arg), Intermediate1(arg) {
> }
>
> };
>
> main() {}

The reason that you are seeing this error is that, according to the
following:

[class.base.init] �12.6.2/6
"All sub-objects representing virtual base classes are initialized by
the constructor of the most derived class (1.8). If the constructor
of the most derived class does not specify a mem-initializer for a
virtual base class V, then V�s default constructor is called to
initialize the virtual base class subobject. If V does not have an
accessible default constructor, the initialization is ill-formed. A
mem-initializer naming a virtual base class shall be ignored during
execution of the constructor of any class that is not the most
derived class."

In your example your virtual base class, Base, does not have a default
constructor and so it becomes necessary to specify a mem-initializer for
it in the constructor of the most derived class which, here, is
Derived. You need:

class Derived : public Intermediate0, public Intermediate1 {
public:
Derived(int arg)
: Base(arg), Intermediate0(arg), Intermediate1(arg)
{ }
};

As specified in the quoted clause the mem-initializers Base(arg) on both
Intermediate0 and Intermediate1's constructors will be ignored.

Regards

Paul Bibbings


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

From: mingze zhang on
On Jun 3, 3:00 am, Mark_Galeck <clcppm-pos...(a)this.is.invalid> wrote:
> Hello,
>
> how to write a non-default constructor for a class that inherits an
> indirect base class, with multiple intermediate classes that list the
> base as virtual? In the SSCCE below, the compiler complains "error:
> no matching function for call to �Base::Base()". Thank you,
>
> Mark
>
> class Base {
> public:
> Base(int) {
> }
>
> };
>
> class Intermediate0: public virtual Base {
> public:
> Intermediate0(int arg) :
> Base(arg) {
> }
>
> };
>
> class Intermediate1: public virtual Base {
> public:
> Intermediate1(int arg) :
> Base(arg) {
> }
>
> };
>
> class Derived: public Intermediate0, public Intermediate1 {
> public:
> Derived(int arg) :
> Intermediate0(arg), Intermediate1(arg) {
> }
>
> };
>
> main() {}

{ quoted banner removed; please do it yourself. -mod }

You only have one copy of the virtual base. The most derived class of
the common virtual base is responsible for initializing the virtual
base, all other initializations are ignored. In your case, class
Derived shall initialize Base.

class Derived: public Intermediate0, public Intermediate1 {
public:
Derived(int arg) :
Base(arg), Intermediate0(arg), Intermediate1(arg) {
}
};

The compiler error is actually saying that, you didn't define default
constructor for Base, so the compiler generated code doesn't compile
(shown as follows),

class Derived: public Intermediate0, public Intermediate1 {
public:
Derived(int arg) :
Base(), Intermediate0(arg), Intermediate1(arg) {
}
};

The initializations in Intermediate0 and Intermediate1 are ignored.


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

From: Andrew Wall on
{ Top-posting is discouraged in the group. -mod }

Mark,
After looking at the other replies about coding the most derived class to call the Base class constructor, you should ask yourself why your base class has a non-default constructor at all!

That constructor will give you plenty of grief as time goes by: You are very likely going to change the inheritance structure and the most derived class will keep changing and a new most derived class will have to take over the responsibility of
initialising Base.

You will be much better off having a default constructed base class, and it looks like the compiler will write the initialiser for you.

Andrew

"Mark_Galeck" <clcppm-poster(a)this.is.invalid> wrote in message news:4d626b8b-9b9c-43b7-ac68-dc1c8683eb81(a)32g2000prq.googlegroups.com...
> Hello,
>
> how to write a non-default constructor for a class that inherits an
> indirect base class, with multiple intermediate classes that list the
> base as virtual? In the SSCCE below, the compiler complains "error:
> no matching function for call to ‘Base::Base()". Thank you,
>
> Mark
>
> class Base {
> public:
> Base(int) {
> }
> };

<snip>

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

From: Hyman Rosen on
On 6/3/2010 3:39 PM, Andrew Wall wrote:
> ask yourself why your [virtual] base class has
> a non-default constructor at all!
>
> That constructor will give you plenty of grief
> as time goes by: You are very likely going to
> change the inheritance structure and the most
> derived class will keep changing and a new most
> derived class will have to take over the
> responsibility of initialising Base.

Which is sometimes exactly what you want. I worked on a
project where each class derived from a Base must have
a different identifying tag, returned by an overridden
virtual getTag method. But many times authors of derived
classes would forget to do this, and the tag would then
be the one from a class lower in the hierarchy. I solved
the problem by making the Base which had the getTag method
require a non-default constructor to which the new tag was
passed. From then on, there was no more forgetting, since
the code would no longer compile without the initializer
being specified in the constructor of each derived class.

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

From: Ulrich Eckhardt on
Hyman Rosen wrote:
> On 6/3/2010 3:39 PM, Andrew Wall wrote:
>> ask yourself why your [virtual] base class has
>> a non-default constructor at all!
>>
>> [...] the most derived class will keep changing and
>> a new most derived class will have to take over the
>> responsibility of initialising Base.
>
> Which is sometimes exactly what you want. I worked on a
> project where each class derived from a Base must have
> a different identifying tag, returned by an overridden
> virtual getTag method. But many times authors of derived
> classes would forget to do this, and the tag would then
> be the one from a class lower in the hierarchy. I solved
> the problem by making the Base which had the getTag method
> require a non-default constructor to which the new tag was
> passed. From then on, there was no more forgetting, since
> the code would no longer compile without the initializer
> being specified in the constructor of each derived class.

While I prefer compile-time errors, too, virtual inheritance introduces some
runtime overhead. Instead, I'd assert() that the virtual function is not
reused by derived classes:

struct base
{
tag get_tag() const
{ return do_get_tag(); }
private:
virtual tag do_get_tag() const;
};

struct derived: base
{
private:
virtual tag do_get_tag() const
{
/* make sure this is not reused by derived
classes, those must supply their own. */
assert(typeid(*this) == typeid(derived));
return derived_tag;
}
}

On the other hand, if you used virtual inheritance but without any virtual
functions, I guess it would perform equally or even better:

struct base
{
explicit base(tag t): m_tag(t) {}
tag get_tag() const
{ return m_tag; }
private:
tag const m_tag;
};

struct derived: virtual public base
{
derived(): base(derived_tag) {}
};

I'd say this comes close to virtual data members, plus forcing derived
classes to override them. Nice, will add that to my toolbox!

Uli

--
Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932


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