Template hierarchy constructor arguments - c++

I'm having trouble understanding why my template hierarchy won't pass constructor arguments deeper than one layer.
So far I've read that it may have something to do with namespacing or template constructors being unnamed. My various attempts at getting the constructor arguments through to the base class with scoping directives have failed.
// test.cc
#include <string>
// Base class, obviously.
template <typename T>
class Base {
public:
Base(const T& t) : _t(t) {}
virtual ~Base() { }
virtual T getVal() const { return _t; }
private:
T _t;
};
// First derivation. This works, although it is explicit.
class DerivedOne : public virtual Base<std::string>
{
public:
DerivedOne(const std::string& path) : Base<std::string>(path) {}
virtual ~DerivedOne() {}
};
// Second derivation. Constructor fails to compile unless I explicitly
// pass the 'path' argument to Base in the initializer list or create a
// default constructor for Base (which, of course, leaves Base::_t
// uninitialized).
class DerivedTwo : public virtual DerivedOne
{
public:
DerivedTwo(const std::string& path) : DerivedOne(path) {}
// This works
// DerivedTwo(const std::string& path) : DerivedOne(path), Base(path) {}
virtual ~DerivedTwo() {}
};
int main()
{
return 0;
}
The compiler complains:
test.cc: In constructor ‘DerivedTwo::DerivedTwo(const string&)’:
test.cc:31:58: error: no matching function for call to ‘Base<std::__cxx11::basic_string<char> >::Base()’
DerivedTwo(const std::string& path) : DerivedOne(path) {}
^
test.cc:7:5: note: candidate: Base<T>::Base(const T&) [with T = std::__cxx11::basic_string<char>]
Base(const T& t) : _t(t) {}
^
test.cc:7:5: note: candidate expects 1 argument, 0 provided
test.cc:5:7: note: candidate: Base<std::__cxx11::basic_string<char> >::Base(const Base<std::__cxx11::basic_string<char> >&)
class Base {
^
test.cc:5:7: note: candidate expects 1 argument, 0 provided
Why do I need to declare a default constructor when it seems that the parameterized constructor should be called? Why must I explicitly pass DerivedTwo's parameter to Base, since I've passed it to DerivedOne (who should pass it to Base)?
Is there some way to avoid this duplication? Does this mean I can't use initializer lists when a base template constructor parameter is allocated on the heap in a derived class initializer list?

What is going on
When you inherit virtually, you are asking that the type you inherit from is a "singleton" within the object heiarchy (not a program-wide singleton, but a instance-wide singleton, strange as that may seem).
As a side effect, the actual most derived class is responsible for constructing the virtual base class, regardless of what intermediate classes exist.
Virtual inheritance is intended when you need to inherit from some class more than once, yet ensure that only one instance exists. Rather than work out some complex set of rules to determine whose constructor call would be the one to be called, the designers of C++ mandated that the most-derived class (the actual one being created) dictates exactly what constructor is called.
Everyone else can chime in, but only if an actual instance of that specific class (and not a more-derived one) is created does their opinion matter.
You probably don't want virtual there
virtual inheritance has almost nothing to do with virtual methods/member functions. Don't use it unless you need to for binary layout or diamond inheritance reasons.
Simply eliminate it from your code, and if you never inherit from a class along 2 different paths to the same most-derived class, you won't miss it.
class DerivedOne : public Base<std::string>
and
class DerivedTwo : public DerivedOne
and your code compiles and does what you seem to want.

When you use virtual inheritance it is always the MOST DERIVED class that initializes the virtual base. Even though your intermediate class passes a value up, it won't do that in further derived classes, which must directly initialize Base.
Since your most derived class (DerivedTwo) doesn't directly initialize Base, then Base is initialized without any parameters passed to it, and so requires a default constructor.
class DerivedTwo : public virtual DerivedOne
{
public:
DerivedTwo(const std::string& path) : Base(path), DerivedOne(path) {}
}
Alternately, stop using virtual inheritance, and just use "normal" inheritance. That is, change this:
class DerivedOne : public virtual Base<std::string>
to this:
class DerivedOne : public Base<std::string>
Unless, of course, you really need virtual inheritance. :)

Related

Virtual Inheritance Base Constructor Mechanics (Diamond Problem) Clarification

The Diamond Problem and Virtual Inheritance are topics that have been discussed endlessly, though while researching them I found myself still uncertain of a few specifics when it comes to calling Base constructors due to the large variety of ways the same terminology was used in different places.
I understood that in the typical Diamond inheritance setup it is the responsibility of the most derived, concrete class to explicitly call the constructor of the base class that is virtually inherited from, lest a default constructor be called (if available); however, I wanted to know exactly what this meant for the constructors of the "middle" classes in the case where the base class does not/cannot have a default constructor.
I did a basic test of this case and would like to confirm that I now correctly understand my findings, just to make sure there are no gotchyas or misconceptions I have.
Note the following code is cutdown to just focus on constructor calls and doesn't demonstrate why I need a diamond inheritance tree in the first place.
class Base
{
private:
std::string mString;
protected:
Base(std::string str) : mString(str) {}
public:
void identify() { std::cout << mString << std::endl; }
};
class DerivedA : public virtual Base
{
public:
DerivedA(std::string str) : Base(str) {}
};
class DerivedB : public virtual Base
{
public:
DerivedB(std::string str) : Base(str) {}
};
class Concrete : public DerivedA, public DerivedB
{
public:
Concrete(std::string str) :
Base(str),
DerivedA("not used"),
DerivedB("not used")
{}
};
int main(int argc, char *argv[])
{
Concrete con("I am concrete");
DerivedA derA("I am DerivedA");
DerivedB derB("I am DerivedB");
con.identify();
derA.identify();
derB.identify();
}
// Output:
// I am concrete
// I am DerivedA
// I am DerivedB
So am I correct in that what happens here is that although I have to call the Base constructor in both Derived classes because there is no default constructor, when Concrete is being constructed the instance of Base is created first via the call to its constructor in Concrete's initialization list, followed by the creation of Derived A and then Derived B; however, in their constructors the call of Base's constructor is ignored, and instead the instance of Base they need that would have resulted from that call is instead provided via a reference to the instance spawned from Concrete's initialization list?
Based on the output, it seems that due to the virtual inheritance the calls to Base's constructor within DerivedA/B's initialization list are only actually used if I instantiate a copy of them directly (which I may actually want to do at times, so this is indeed useful), otherwise the calls to the Base constructor in the most derived class essentially "override" the same constructor calls in the classes higher up the inheritance tree.
Do I understand this correctly?

Avoid copying all constructors in subclasses

So a base class has multiple constructors:
sf::Sprite()
sf::Sprite(const Texture& texture)
sf::Sprite(const Texture& texture, const IntRect& rectangle)
And I'm subclassing this class multiple times:
class Sub : public sf::Sprite {
public:
Sub() : sf::Sprite() {};
Sub(const Texture& texture) : sf::Sprite(texture) {};
Sub(const Texture& texture, const IntRect& rectangle) : sf::Sprite(texture, rectangle) {};
// My subclass specific code
};
As you see, I have to repeat these three constructors for every subclass. Is there a way to avoid this, since the constructors usually don't do anything special? Sometimes I need some class specific initialization though, so it's not always viable to just straight out copy everything.
You can accomplish this by inheriting constructors (since C++11).
If the using-declaration refers to a constructor of a direct base of the class being defined (e.g. using Base::Base;), all constructors of that base (ignoring member access) are made visible to overload resolution when initializing the derived class.
e.g.
class Sub : public sf::Sprite {
public:
using sf::Sprite::Sprite;
// My subclass specific code
};
If the inherited constructors is used to initialize a Sub, the sf::Sprite subobject is initialized using the inherited constructor, and all other members of Sub are initialized as if by the defaulted default constructor.
If there're some special cases need to be processed, you still can define constructor(s) in Sub, the inherited constructor with the same signature will be hidden.
As with using-declarations for any other non-static member functions, if an inherited constructor matches the signature of one of the constructors of Derived, it is hidden from lookup by the version found in Derived.
You can use the using keyword to inherit the constructor of your base class, excluding the special ones (default, copy, move). To shorten your default constructor simply use = default. If you want class specific initialization you can simply write the constructor again, just as you do now.
class Sub : public sf::Sprite {
public:
Sub() = default;
using sf::Sprite::Sprite;
Sub(const Texture& texture)
{
// your custom code.
};
// My subclass specific code
};
If you can just 'inherit' the constructor, i.e. have one with exactly the same arguments, simply use using as explained in the other answers. However, if your derived class's constructor has additional arguments and/or requires some class specific initialization, you may use a variadic template.
struct base
{
base(int);
base(std::string const&);
base(some_type const&);
base(std::string const&, some_type const&);
/* ... */
};
struct derived : base
{
template<typename...Args>
derived(some_other_type const&x, Args&&...args)
: base(std::forward<Args>(args)...)
, private_datum(x)
{
construction_details(); // class-specific initialisation
}
private:
some_other_type private_datum;
void construction_details(); // implemented in source code
};

Calling constructor of non-template base class through template class constructor in initialization list

I've come across a problem in a class hierarchy I couldn't solve so far. Below you get the minimal example where the template Base class itself inherits from another class that is not a template (called AbsoluteBase in the example below). The class Derived then inherits from Base with its template argument also being Bases' template argument:
#include <iostream>
using namespace std;
class AbsolutBase {
protected:
int number;
AbsoluteBase(int _number) {
number = _number;
}
virtual ~AbsoluteBase() {}
virtual void print() const = 0;
};
template <typename T> class Base : virtual public AbsoluteBase {
public:
Base(int _number) : AbsoluteBase(_number) {}
virtual void print() const {
cout << number << endl;
}
};
template <typename T> class Derived : public Base<T> {
public:
Derived(int _number) : Base<T>::Base(_number) {}
};
int main() {
Derived<char> object(100);
object.print();
}
So each constructor calls the constructor of its parent and passes an integer as argument all the way down to AbsoluteBase. But when compiling the code I get:
error: no matching function for call to 'AbsoluteBase::AbsoluteBase()'
note: candidates are: AbsoluteBase::AbsoluteBase(int)
note: candidate expects 1 argument, 0 provided
Making an instance of Base works just fine but when calling its constructor in the initialization list of Derived, the compiler wants AbsolutBase() as constructor even though the integer argument is given. Obviously, when defining a default constructor in AbsoluteBase the print() function outputs garbage as no value has been passed to number.
So something has to be wrong with my call of Base<T>::Base(int) but I can't see what it is. I am grateful for every explanation and help!
Greetings,
Benniczek
AbsoluteBase is a virtual base class. As such, it must be initialized by the constructor of the most-derived class. Your initializer AbsoluteBase(_number) is valid, but it is only used if you instantiate an object of type Base<T> directly.
The best solution is probably not to make AbsoluteBase a virtual base class.
The reason for this rule is:
class Silly: public Base<int>, Base<long>
{
public:
Silly() : Base<int>::Base(1), Base<long>::Base(2) {}
};
There is only one AbsoluteDerived object (that's what virtual means in this context), so is it initialized with 1 or 2?
Because of virtual inheritance. When base class inherits virtually from another class, the child class of base it must also call constructor of virtual parent of its parent. Since you didn't do this, compiler is trying to call no-argument AbsoluteBase's ctor. So you just have to code as follows:
template <typename T> class Derived : public Base<T> {
public:
Derived(int _number) : AbsoluteBase(_number), Base<T>::Base(_number) {}
};
You declared Absolute Base as class AbsolutBase without the e. Compiles just fine with the typo fixed.
Edit: It also will not compile if you have class base doing virtual inheritance from Absolute. Unless you need virtual inheritance (using multiple inheritance?) you can declare it class Base : public AbsoluteBase
If you do need virtual inheritance (the diamond problem) you'll need to initialize AbsoluteBase in your Derived class. Given that Base virtually inherits from AbsoluteBase, Derived could also inherit from a Base2 which also virtually inherits from AbsoluteBase (this is the point of virtual inheritance, one class can inherit from two different classes that themselves inherit from a common base). As it is a virtual inheritance, there can be only 1 AbsoluteBase even though Base and Base2 could inherit from AbsoluteBase, so how does it get initialized? This is why Derived is required to initialize it directly, so that when the 1 copy of AbsoluteBase is made, it is well understood how it will be initialized.
Again, that is messy, if you don't need virtual inheritance (you probably don't I'd guess...) you can just make Base inherit from AbsoluteBase publically and call it a day.

Virtual but not multiple inheritance to call grandparent constructor

I'm having this kind of code:
class Ref {<undefined>};
Ref refObjectForA, refObjectForB;
class Base
{
public:
Base(const Ref & iRef) : _ref(iRef) {}
virtual ~Base() {}
const Ref & ref;
};
class A: public Base
{
public:
A() : Base(refObjectForA) {}
virtual ~A() {}
};
class B: public A
{
public:
B() : Base(refObjectForB) {} // won't compile: Base is not direct base of B
virtual ~B() {}
};
As the attribute is a reference, I think I can only set it in constructor, so I need to call Base constructor in B().
I've found two ways: providing a "forward" constructor in A (but this implies adding code in all classes that might be inherited):
A(const Ref& iRef): Base(iRef)
or using virtual inheritance:
class A: public virtual Base
Second option allows more straightforward code in B implementation but I'm wondering if I'm misusing virtual inheritance in an ugly trick or if it is a valid usecase.
Can I use virtual inheritance in this case?
If no, for what reason?
One of the "unexpected" behaviors I've found is that it's not possible to static_cast a Base pointer to a B pointer because of the virtual inheritance.
Moreover I'm also wondering why it works (I mean why a B().ref == refObjectForB): I would think that the implicit call to default A() constructor in B() would overwrite the ref attribute after explicit Base constructor, but maybe it's not true with virtual inheritance.
The best option I can see if you want to stick to your inheritance hierarchy is to implement protected constructors taking a reference which they'll forward to the Base class. Making a constructor protected makes sure that a (final) instance can't be constructed using this constructor, so it will only be used in subclasses to initialize the super classes.
With some more or less ugly and dangerous macro, this becomes easy to be written:
#define REF_FORWARD_CTOR(ClassName, DirectSuperClassName) \
protected: ClassName(class Ref &r) : DirectSuperClassName(r) {} \
public:
class A : public Base
{
REF_FORWARD_CTOR(A, Base)
public:
A() : Base(refObjectForA) {} // normal ctor
};
class B : public A
{
REF_FORWARD_CTOR(B, A)
public:
B() : A(refObjectForB) {} // normal ctor
};
An alternative design would be to let A and B both derive (directly) from Base. Then, add functionalities by using multiple inheritance and "common classes", maybe private, depending on what they are for:
class Base {
};
class Common {
// common stuff used by both A and B
};
class A : public Base, public Common {
// no further stuff here
};
class B : public Base, public Common {
// add more stuff, or put it in a common super-class again,
// if some classes want to inherit from B again
};
The problem with this design is that functionality in Common can't access the stuff in A and B. To solve this, do one of the following:
If only static stuff is required: Use CRTP to specify A / B in a concrete Common type: Common<A> can then use A::..., but doesn't have anything to do with a concrete instance of A
If an instance is required: provide a pointer / reference in the constructor of Common (slight overhead)
Putting the first two solutions together: Use CRTP, implement wrapper functions in A and B which call functions in Common<A> and Common<B> providing this (which is a A* or B* via an extra parameter.
Same as above, but the class Common can also be non-templated (no CRTP) if you overload / template these functions on this pointer argument ("CRTP on functions", if you want to call it like that). Code speaks louder than words. (Example code is without your references and focuses on the "common class".)
Yes you can technically use virtual inheritance to achieve the goal of providing the reference in the most derived class.
And yes, that's a design smell.
Your classes should not need to be aware of anything but their immediate bases (virtual inheritance is the exception to the rule, when it's needed for other reasons).
Sticking to the proposed classes hierarchy, in order to solve the problem it is enough to use the "using-declaration" to bring the Base's constructor to the protected part of the class A, i.e.:
class A: public Base
{
public:
A() : Base(refObjectForA) {}
virtual ~A() {}
protected:
using Base::Base;
};

How do I call the base class constructor?

Lately, I have done much programming in Java. There, you call the class you inherited from with super(). (You all probably know that.)
Now I have a class in C++, which has a default constructor which takes some arguments. Example:
class BaseClass {
public:
BaseClass(char *name); ....
If I inherit the class, it gives me the warning that there is no appropriate default constructor available. So, is there something like super() in C++, or do I have to define a function where I initialize all variables?
You do this in the initializer-list of the constructor of the subclass.
class Foo : public BaseClass {
public:
Foo() : BaseClass("asdf") {}
};
Base-class constructors that take arguments have to be called there before any members are initialized.
In the header file define a base class:
class BaseClass {
public:
BaseClass(params);
};
Then define a derived class as inheriting the BaseClass:
class DerivedClass : public BaseClass {
public:
DerivedClass(params);
};
In the source file define the BaseClass constructor:
BaseClass::BaseClass(params)
{
//Perform BaseClass initialization
}
By default the derived constructor only calls the default base constructor with no parameters; so in this example, the base class constructor is NOT called automatically when the derived constructor is called, but it can be achieved simply by adding the base class constructor syntax after a colon (:). Define a derived constructor that automatically calls its base constructor:
DerivedClass::DerivedClass(params) : BaseClass(params)
{
//This occurs AFTER BaseClass(params) is called first and can
//perform additional initialization for the derived class
}
The BaseClass constructor is called BEFORE the DerivedClass constructor, and the same/different parameters params may be forwarded to the base class if desired. This can be nested for deeper derived classes. The derived constructor must call EXACTLY ONE base constructor. The destructors are AUTOMATICALLY called in the REVERSE order that the constructors were called.
EDIT: There is an exception to this rule if you are inheriting from any virtual classes, typically to achieve multiple inheritance or diamond inheritance. Then you MUST explicitly call the base constructors of all virtual base classes and pass the parameters explicitly, otherwise it will only call their default constructors without any parameters. See: virtual inheritance - skipping constructors
You have to use initiailzers:
class DerivedClass : public BaseClass
{
public:
DerivedClass()
: BaseClass(<insert arguments here>)
{
}
};
This is also how you construct members of your class that don't have constructors (or that you want to initialize). Any members not mentioned will be default initialized. For example:
class DerivedClass : public BaseClass
{
public:
DerivedClass()
: BaseClass(<insert arguments here>)
, nc(<insert arguments here>)
//di will be default initialized.
{
}
private:
NeedsConstructor nc;
CanBeDefaultInit di;
};
The order the members are specified in is irrelevant (though the constructors must come first), but the order that they will be constructed in is in declaration order. So nc will always be constructed before di.
Regarding the alternative to super; you'd in most cases use use the base class either in the initialization list of the derived class, or using the Base::someData syntax when you are doing work elsewhere and the derived class redefines data members.
struct Base
{
Base(char* name) { }
virtual ~Base();
int d;
};
struct Derived : Base
{
Derived() : Base("someString") { }
int d;
void foo() { d = Base::d; }
};
Use the name of the base class in an initializer-list. The initializer-list appears after the constructor signature before the method body and can be used to initialize base classes and members.
class Base
{
public:
Base(char* name)
{
// ...
}
};
class Derived : Base
{
public:
Derived()
: Base("hello")
{
// ...
}
};
Or, a pattern used by some people is to define 'super' or 'base' yourself. Perhaps some of the people who favour this technique are Java developers who are moving to C++.
class Derived : Base
{
public:
typedef Base super;
Derived()
: super("hello")
{
// ...
}
};
There is no super() in C++. You have to call the Base Constructor explicitly by name.