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
};
Related
std::basic_ios has a public constructor:
explicit basic_ios (std::basic_streambuf<CharT,Traits>* sb);
IMO, the sole reason for a class to have a public constructor is to use a standalone instance of that class in a program. If a class exists only to have other classes descend from it (as seems to be the case for basic_ios), all of the class's constructors should be protected. The constructors of std::ios_base are all protected. But, for some reason, the designers of the standard made this one constructor of basic_ios public.
basic_ios is used as a base class for several stream types, and I can't envision a use case where you'd have one that wasn't at least a basic_istream or basic_ostream. Is there one?
The other reason for a class to have a public constructor is to have this constructor signature available to construct a derived object:
struct B{
B(int);
protected:
~B();
};
struct A:B{
private://no effect.
using B::B;
public:
A(void*);
};
A a(10);
The constructor must be public in the base class because a using declaration of a base constructor does not change the accessibility of the inherited constructor.
What I failed to notice was that std::basic_istream, std::basic_ostream and std::basic_iostream also had public constructors (each takes a std::basic_streambuf*).
This allows for a generic-programming analogue of polymorphism, in the same vein as the pimpl idiom.
That is, this way you can create a specialized streambuf type and use it in a basic_[io]stream without having to create specialized stream classes. (The functionality is limited: You can't assign a new buffer to the same stream, and you have to externally keep track of the buffer's lifetime and ownership).
The specialized basic_[io]fstream and basic_[io]stringstream each contain a full instance of the associated buffer type. This means an instance of a specialized stream type will only work with its internal buffer and not another, not even one of the same type. Using a raw basic_[io]stream is a (clunky) workaround to this.
template<class C, class TR>
class snazzy_filebuf: public std::basic_streambuf<C, TR>
{
protected:
typename TR::int_type overflow(TR::int_type) override;
typename TR::int_type underflow(TR::int_type) override;
typename TR::int_type pbackfail(TR::int_type) override;
public:
snazzy_filebuf();
};
.....
snazzy_filebuf<char> buf;
std::basic_ostream<char> o_s(&buf);
o_s << "Hello, world\n";
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. :)
Consider following code:
class TBase {
public:
TBase();
TBase(const TBase &);
};
class TDerived: public TBase {
public:
using TBase::TBase;
};
void f() {
TBase Base;
TDerived Derived(Base); // <=== ERROR
}
so, I have base and derived classes, and want to use "using TBase::TBase" to pull copy ctor from base class to be able to create instance of derived class in such way:
TDerived Derived(Base);
But all compilers rejects this with these error messages
7 : note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'TBase' to 'const TDerived' for 1st argument
Why? What am I doing wrong? Why "using TBase::TBase" does not work in this situation?
UPDATE
How can be explained following piece of code from cppreference.com?
struct B1 {
B1(int);
};
struct D1 : B1 {
using B1::B1;
// The set of inherited constructors is
// 1. B1(const B1&)
// 2. B1(B1&&)
// 3. B1(int)
Copy and move consturctors (and the default constructor) are never inherited, simply because the standard says so. All other constructors are.
That comment on cppreference was misleading(1). The same comment in the standard says:
The candidate set of inherited constructors in D1 for B1 is
(Emphasis mine).
The standard then goes on to say that only the D1(int) constructor is actually inherited. The copy and move constructors for D1 are implicitly-declared as for any other class, not inherited.
Refer to C++14 12.9 [class.inhctor] for details.
(1) I submitted a change to cppreference to hopefully clarify this.
If you further read the same piece of code, it says:
// D1 has the following constructors:
// 1. D1()
// 2. D1(const D1&)
// 3. D1(D1&&)
// 4. D1(int) <- inherited
};
Thus a copy ctor is still the copy ctor, it accepts an argument of class TDerived. D1(int) is generated automatically nevertheless.
As per standard 12.6.3/p1 Initialization by inherited constructor [class.inhctor.init] (Emphasis Mine):
When a constructor for type B is invoked to initialize an object of a
different type D (that is, when the constructor was inherited
(7.3.3)), initialization proceeds as if a defaulted default
constructor were used to initialize the D object and each base class
subobject from which the constructor was inherited, except that the B
subobject is initialized by the invocation of the inherited
constructor. The complete initialization is considered to be a single
function call; in particular, the initialization of the inherited
constructor’s parameters is sequenced before the initialization of any
part of the D object.
Thus, constructors are not actually inherited but rather they're implicitly or explicitly called by the respective derived constructor. Also keep in mind that the inherited constructors are simply calling the base constructors and do not perform any member initialization in the derived object.
To clarify this consider the following example:
struct Base {
Base(int);
...
};
struct Derived : Base {
using Base::Base;
...
};
The above Derived class definition is syntactically equivalent with:
struct Derived : Base {
Derived(int i) : Base(i) {}
...
};
That is, the using declaration in the Derived class implicitly defines the constructor Derived(int). At this point mind also that if the constructor is inherited from multiple base class sub-objects Derived, the program is ill-formed.
In the same manner you've been lead to the logical conclusion that since I've declared in the base class a copy constructor with the using declaration:
class TBase {
public:
TBase();
TBase(const TBase &);
};
class TDerived: public TBase {
public:
using TBase::TBase;
};
I would get the following syntactical equivalent Derived class:
class TDerived: public TBase {
public:
TDerived() : Base() {}
TDerived(TBase const &other) : Base(other) {}
};
However, this is not the case. You can't "inherit" a copy constructor neither a default constructor neither a move constructor. Why? because this is how the C++ standard dictates so.
What you can do instead is to define a user defined constructor that will take as input a base class object:
class TDerived: public TBase {
public:
TDerived(TBase const &other) {}
};
After all TDerived and TBase are different classes even though the first inherits the second one.
I am overloading operator= on a struct EqualTestBase, and operator= takes different parameters than are used to construct the struct.
struct EqualTestBase
{
EqualTestBase(int one) {}
EqualTestBase& operator=(std::string two)
{
//stuff
return *this;
}
};
It works fine on the base class. But a trival struct derived from it, EqualTestDerived, acts like it doesn't have the operator= member function.
struct EqualTestDerived : public EqualTestBase
{
EqualTestDerived(int one) : EqualTestBase(one) {}
};
void test()
{
EqualTestBase basetest(0);
basetest = "test"; //this is fine, compiles
EqualTestDerived derivedtest(0);
derivedtest = "test"; //this does not compile, says there is no constructor that takes type const char[5]
}
Do I have to redefine operator= on all derived structs, or is there a way to automatically pass down that functionality?
The derived class has an implicitly-declared copy-assignment operator, which hides the one declared in the base class. You can use using to bring it into scope:
struct EqualTestDerived : public EqualTestBase
{
EqualTestDerived(int one) : EqualTestBase(one) {}
using EqualTestBase::operator=;
};
operator= isn't inherited. If a class doesn't define operator= itself, the compiler will synthesize one for it (regardless of the fact that its base class does define an operator=).
If you want something that can be inherited (and can be virtual) you generally want to define it as a function with a different name. The generally accepted name for such a function is clone (though clone is normally more like a copy constructor, creating a new instance of an object, not just assigning to an existing one).
I have a diamond-shaped hierarchy of classes, where there is no default constructor, nor copy constructors. The two constructors I have are a "move" one and another that takes a lvalue reference to an object:
struct base {
base(base&&) = default;
base(member_type&& m): member_(std::move(m)) {}
member_type member_;
};
struct virt_1: virtual base {
virt_1(virt_1&& rhs): base(std::move(rhs)) {}
virt_1(member_type&& m): base(std::move(m)) {}
};
struct virt_2: virtual base {
virt_2(virt_2&& rhs): base(std::move(rhs)) {}
virt_2(member_type&& m): base(std::move(m)) {}
};
struct concrete: virt_1, virt_2 {
concrete(concrete&& rhs) // ???
};
Besides not using a diamond-shaped hierarchy, is it possible to implement the move constructor for the concrete class?
Thanks!
What's wrong with asking the compiler to provide the implementation?
concrete(concrete&&) = default;
I'd define the virt_1 and virt_2 move constructors as defaulted too.
You could write it out if you really wanted to:
concrete(concrete&& rhs)
: base(std::move(rhs)), virt_1(std::move(rhs)), virt_2(std::move(rhs))
{ }
Or if you really like typing:
concrete(concrete&& rhs)
: base(static_cast<base&&>(rhs)),
virt_1(static_cast<virt_1&&>(rhs)),
virt_2(static_cast<virt_2&&>(rhs))
{ }
The initializers for the virt_1 and virt_2 bases are useless, because they only call the base constructor and as it's a virtual base they won't do that when concrete has called it, but due to your choices of constructors you can't default-construct them and are required to initialize them with an rvalue even though they'll do nothing with it.
Sure. Any constructor with a virtual base somewhere in the hierarchy is responsible for initializing that base. Essentially any class below the virtual base in the hierarchy inherits permission to initialize the base.
In this case, the default move constructor should do the right thing. I would recommend also specifying concrete : private virtual base to clarify what's happening.
Here is a working demo.