Prev: Container adapter to treat a sorted vector as a set
Next: accumulating number of chars in vector<string>
From: Paul Bibbings on 2 Jun 2010 17:26 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 2 Jun 2010 17:31 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 3 Jun 2010 04:39 { 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 3 Jun 2010 14:27 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 3 Jun 2010 23:34 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! ]
First
|
Prev
|
Pages: 1 2 Prev: Container adapter to treat a sorted vector as a set Next: accumulating number of chars in vector<string> |