I tried extending std::ifstream with one function to make it easier to read binary variables, and to my surprise, with using std::ifstream::ifstream; the move constructor is not inherited. Worse yet, it is explicitly deleted.
#include <fstream>
class BinFile: public std::ifstream
{
public:
using std::ifstream::ifstream;
//BinFile(BinFile&&) = default; // <- compilation warning: Explicitly defaulted move constructor is implicitly deleted
template<typename T>
bool read_binary(T* var, std::streamsize nmemb = 1)
{
const std::streamsize count = nmemb * sizeof *var;
read(reinterpret_cast<char*>(var), count);
return gcount() == count;
}
};
auto f()
{
std::ifstream ret("some file"); // Works!
//BinFile ret("some file"); // <- compilation error: Call to implicitly-deleted copy constructor of 'BinFile'
return ret;
}
I don't want to explicitly implement the move constructor because it just feels wrong. Questions:
Why it is deleted?
Does it makes sense for it to be deleted?
Is there a way to fix my class so that the move constructor is properly inherited?
The issue is that basic_istream (a base of basic_ifstream, of which template ifstream is an instantiation) virtually inherits from basic_ios, and basic_ios has a deleted move constructor (in addition to a protected default constructor).
(The reason for virtual inheritance is that there is a diamond in the inheritance tree of fstream, which inherits from ifstream and ofstream.)
It's a little known and/or easily forgotten fact that the most derived class constructor calls its (inherited) virtual base constructors directly, and if it does not do so explicitly in the base-or-member-init-list then the virtual base's default constructor will be called. However (and this is even more obscure), for a copy/move constructor implicitly defined or declared as defaulted, the virtual base class constructor selected is not the default constructor but is the corresponding copy/move constructor; if this is deleted or inaccessible the most derived class copy/move constructor will be defined as deleted.
Here's an example (that works as far back as C++98):
struct B { B(); B(int); private: B(B const&); };
struct C : virtual B { C(C const&) : B(42) {} };
struct D : C {
// D(D const& d) : C(d) {}
};
D f(D const& d) { return d; } // fails
(Here B corresponds to basic_ios, C to ifstream and D to your BinFile; basic_istream is unnecessary for the demonstration.)
If the hand-rolled copy constructor of D is uncommented, the program will compile but it will call B::B(), not B::B(int). This is one reason why it is a bad idea to inherit from classes that have not explicitly given you permission to do so; you may not be calling the same virtual base constructor that would be called by the constructor of the class you are inheriting from if that constructor were called as a most-derived class constructor.
As to what you can do, I believe that a hand-written move constructor should work, since in both libstdc++ and libcxx the move constructor of basic_ifstream does not call a non-default constructor of basic_ios (there is one, from a basic_streambuf pointer), but instead initializes it in the constructor body (it looks like this is what [ifstream.cons]/4 is saying). It would be worth reading Extending the C++ Standard Library by inheritance? for other potential gotchas.
As the previous answer mentioned the constructor is defined as deleted in the base class.
It means, you can't use it - see <istream>:
__CLR_OR_THIS_CALL basic_istream(const basic_istream&) = delete;
basic_istream& __CLR_OR_THIS_CALL operator=(const basic_istream&) = delete;
And the return ret tries to use the deleted copy constructor and not the move constructor.
However if you crate your own move constructor it should work:
BinFile(BinFile&& other) : std::ifstream(std::move(other))
{
}
You can see this in one of the comments of your question (#igor-tandetnik).
Related
This question already has answers here:
Why does the implicit copy constructor calls the base class copy constructor and the defined copy constructor doesn't?
(3 answers)
Closed 11 months ago.
Consider the following example:
class A
{
public:
A()
{
cout<<"constructor A called: "<<this<<endl;
};
A(A const& other) = default;
};
class B : public A
{
public:
B()
{
cout<<"constructor B called: "<<this<<endl;
};
//This calls A's constructor
B(B const& other)
{
cout<<"B copy constructor called: "<<this<<endl;
};
//While this doesn't call A's constructor
//B(B const& other) = default;
};
int main()
{
B b;
B b2(b);
cout<<"b: "<<&b<<endl;
cout<<"b2: "<<&b2<<endl;
return 0;
}
Output:
constructor A called: 0x7fffc2fddda8
constructor B called: 0x7fffc2fddda8
constructor A called: 0x7fffc2fdddb0
B copy constructor called: 0x7fffc2fdddb0
b: 0x7fffc2fddda8
b2: 0x7fffc2fdddb0
Why is the constructor of A is called when copying B?
Shouldn't the copy constructor of A be called instead?
However, if you change class B's copy constructor to be default, the constructor of A is not called when copying which makes sense.
It will be nice if someone can give a reasonable explanation as to why.
Why is the constructor of A is called when copying B? Shouldn't the copy constructor of A be called instead?
No, it shouldn't.
A derived class must always initialize a base class. If the derived class has a constructor that is implemented explicitly by the user, but it does not explicitly call a base class constructor in its member initialization list, the compiler will make an implicit call to the base class's default constructor, regardless of the type of the derived constructor. The compiler does not make any assumption about the user's intent in implementing the derived constructor. If the user wants a specific base class constructor to be called, they need to make that call themselves.
Since B has an explicitly implemented copy constructor that lacks a member initialization list, the compiler initializes A by calling its default constructor, not its copy constructor.
IOW, this:
B(B const& other)
{
...
}
Is equivalent to this:
B(B const& other) : A()
{
...
}
NOT to this, as you are thinking:
B(B const& other) : A(other)
{
...
}
However, if you change class B's copy constructor to be default, the constructor of A is not called when copying which makes sense.
Correct, a default'ed copy constructor will call the base class's copy constructor, not its default constructor. The compiler is implicitly implementing the entire derived constructor, and so it will choose the appropriate base class constructor to call.
One of the requirements of constructor inheritance is that the derived class can not have any constructors with the same signature. I am unsure however about how deleted functions behave under these rules.
class Foo
{
public:
Foo() = delete;
Foo(const Foo& a_Foo) = delete;
Foo(int a_Value) : m_Value(a_Value) {}
private:
int m_Value;
};
class Bar : public Foo
{
public:
using Foo::Foo;
Bar() : Foo(7) {};
Bar(const Bar& a_Bar) : Foo(12) {};
};
Are deleted constructors inherited at all?
If so, Bar() and Foo() have the same signature, does this make the code invalid?
You could argue that Foo(const Foo& a_Foo) and Bar(const Bar& a_Bar) have different signatures. How do copy constructors behave under constructor inheritance?
Default, copy, and move constructors are not inherited, nor can inheriting a constructor implicitly declare a copy or move constructor for the derived class. Also, an inheriting constructor declaration will essentially just "skip over" a base class constructor if there's already a constructor with the same signature in the derived class.
For each non-template constructor in the candidate set of inherited constructors other than a constructor
having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly
declared with the same constructor characteristics unless there is a user-declared constructor with the same
signature in the complete class where the using-declaration appears or the constructor would be a default,
copy, or move constructor for that class.
([class.inhctor]/3)
Also, an inherited constructor is deleted if the corresponding base class constructor is deleted.
A constructor so declared has the same access as the corresponding constructor in X. It is deleted if the
corresponding constructor in X is deleted (8.4). An inheriting constructor shall not be explicitly instantiated (14.7.2) or explicitly specialized (14.7.3).
([class.inhctor]/4)
Foo constructor is deleted, so you can't define a constructor of class Bar that uses deleted Foo constructor. It doesn't make sense to talk about inheritance there, because you can never create an object of class Bar that uses deleted Foo constructor.
Are deleted constructors inherited at all?
No. They are deleted, there is nothing to inherit from.
If so, Bar() and Foo() have the same signature, does this make the
code invalid?
Default constructor can't be inherited.
You could argue that Foo(const Foo& a_Foo) and Bar(const Bar& a_Bar)
have different signatures. How do copy constructors behave under
constructor inheritance?
Copy constructors can't be inherited as well.
Consider the following example:
class Symbol {
public:
Symbol() = delete;
Symbol(char ch) : c{ch} {}
private:
char c;
//
};
class Derived : Symbol {
public:
private:
int i;
};
class NotDerived {
public:
private:
int i;
};
The following line would not compile. You cannot create an object of a class with a deleted constructor. Everyone knows that.
// Can't create an object because of deleted constructor.
Symbol sym;
However, you can create the object of the base class using the overloaded constructor:
// Parametrized constructor, this one is fine.
Symbol sym_char('a');
The Derived class, using : public inheritance, inherits everything from the base Symbol class, including the deleted constructor. Indeed, if the Symbol class has a deleted constructor, disallowing you to create objects of that class using the default constructor, then logically the Derived class should also forbid you to create objects of that class using the deleted constructor.
// note: default constructor of 'Derived' is implicitly deleted because base class 'Symbol' has a deleted default constructor
// The deleted consturctor is inherited from the base class.
Derived d;
The Derived class inherits all and any methods from the Symbol class, including any deleted constructors!
If you take away the inheritance statement, observe that the inherited deleted constructor disappears. There is no deleted constructor any more. Now the default compiler generated default constructor comes back, because the deleted constructor isn't overwriting it.
// No deleted constructor: works
NotDerived nd;
The NotDerived class has a compiler generated default constructor, because it is not inheriting from anything. The Derived class does not have a default constructor, it has a deleted constructor, because it inherits from a class that has a deleted constructor.
So as we see in the above experiments, yes all and any methods that are in the base class including deleted ones get inherited into the derived class. This means that yes deleted constructors in base classes do get inherited into derived classes!
Let's say that I have two classes
Base manages some memory. It has working move, swap, assignment and destructor.
Derived does not add anything new that need need to be managed (no new memory allocations).
class Base
{
public:
Base();
Base(const Base& other);
friend void swap(Base& a, Base& b);
Base(Base&& other);
protected:
int** some2Darray;
int w, h;
};
class Derived : public Base
{
public:
Derived();
//...?
};
Do I need to implement all those functions in derived class for it to be good? How to reuse those functions from base class? I don't need to manage any more memory in this class.
How those function would look if I added member to Derived class? Should I totally rewrite all those functions or is there some way to use for example "copy" base class and just copy that one added member additionally in copy constructor?
You can inherit (edit: yeah, well this is not true inheritance, maybe this shall be noted explicitly) constructors since c++11. Via
class Derived : public Base
{
public:
Derived();
using Base::Base; // <-- this will import constructors
};
But this will not take care of any extras!
However, you do not need to copy code. You can just call parent functions.
E.g:
class Derived : public Base
{
int extra;
public:
Derived() : Base(), extra(42){};
Derived(const Derived& other) : Base(other) {extra = other.extra;};
void copy(const Derived& other);
friend void swap(Derived& a, Derived& b);
};
void Derived::copy(const Derived& other){
Base::copy(other);
extra = other.extra;
}
Also don't forget about virtual destructor.
EDIT:
For swap I would just cast derived instances to their bases to make compiler use the swap defined for parent type. Then swap extra stuff.
void swap(Derived& a, Derived& b){
swap(static_cast<Base&>(a), static_cast<Base&>(b));
swap(a.extra, b.extra);
}
First of all: constructors, assignment operators and destructors are not inherited (*). Instead, they may, in some circumstances, be synthesized automatically for you by the compiler.
So, when do you need to write them ? Only when the default generated version does not correspond to your needs:
the accessibility is not what you wish (it's always public)
the method should be deleted
the default behavior is incorrect (shallow copy, for example)
the compiler cannot synthesize the method for you
Regarding the latter two points:
the Rule of Three states that if you write any one of the Copy Constructor, Copy Assignment Operator or Destructor; you should provide the other two as well
in C++11, if you write any of those 3 special methods, then the Move Constructor and Move Assignment Operator are not synthesized automatically
in C++11, if you write either a Move Constructor or Move Assignment Operator, then none of those 3 special methods is synthesized automatically either
(*) The C++11 feature called inheriting constructors is ill-named, it is more delegating than inheriting.
That being said, if Derived does not have any tricky attribute, then you can probably avoid writing those members. If you still wish to write them (to avoid inlining for example), you should be able to use the = default syntax:
// Derived.h
class Derived: public Base {
public:
Derived(Derived const&) = default;
Derived& operator(Derived const&);
};
// Derived.cpp
Derived& Derived::operator=(Derived const&) = default;
I'm not sure about the move operator, but you don't have to implement copy ctor, destructor and copy operator as the standard functions will automatically call the corresponding functions from all base classes.
EDIT: see also How to use base class's constructors and assignment operator in C++?
I want to make an abstract base class non-copyable and force any classes that derive from it to be non-copyable. The below code uses Boost's noncopyable as defined in noncopyable.hpp yet still allows D, the derived class, to define a copy constructor.
class noncopyable
{
protected:
noncopyable() {}
~noncopyable() {}
private: // emphasize the following members are private
noncopyable( const noncopyable& );
const noncopyable& operator=( const noncopyable& );
};
class D : noncopyable
{
public:
D() { }
D(const D&) { }
};
int main()
{
D a;
D b(a);
return 0;
}
This code compiles and runs (http://ideone.com/g4gGLm), when I expected it to throw a compile-time error about D's copy constructor. Maybe I have misinterpreted what this noncopyable class is meant to do. If so, is there any way to force derived classes to not define a copy constructor? (Answer can use C++11, but preferably not boost)
The reason this works is because D(const D&) calls the default constructor of the base class, not the copy constructor. (counter-intuitive at first, but it makes sense considering all constructors behave like this)
Since the copy constructor isn't called, a copy of the base object isn't created unless you explicitly ask for one:
D(const D& d) : noncopyable(d) { }
which would indeed result in an error. So in fact, your issue is a non-issue - there's no copying of noncopyable going on.
I'm not aware of any straight-forward way to force a derived class do disallow copying, nor would I recommend using one if there was.
You need to delete the copy constructor of D. Right now you allow copy-construction of D's by not trying to copy-construct the base class. The following variants will not compile:
class E: noncopyable
{
};
E e, e2(e);
class F: noncopyable
{
public:
F(const F &init): noncopyable(init)
{}
};
Suppose I have a base class Person and I publicly inherit a class Teacher from base class Person.
Now in the main function I write something like this
// name will be passed to the base class constructor and 17
// is for derived class constructor.
Teacher object(“name”,17) ;
Teacher object1=object; //call to copy constructor
Now I have not written the copy constructor for both the classes, off course the default copy constructors will be called. The Person class’s default copy constructor will first call the base class’s copy constructor.
Now the problem is suppose I write the copy constructor for the base class only, what happens is, the default copy constructor of the derived class will call my written copy constructor.
Now suppose I write the copy constructor for both the classes . now the copy constructor of the derived class (i.e Teacher) will call the default constructor of the base class but not the copy constructor why?
Is only default copy constructor of the derived class can call the copy constructor of the base class automatically?
You have to call the base copy constructor explicitly:
Teacher(const Teacher& other)
: Person(other) // <--- call Person's copy constructor.
, num_(other.num_)
{
}
Otherwise Person's default constructor will be called.
I seem to not fully understand the question so I'll just say everything I think is relevant and hopefully this will help the OP.
All user defined constructors call their base's default constructor by default (unless they explicitly call a different constructor), it doesn't matter if the base's default constructor is user defined or compiler generated.
When a copy constructor is generated by the compiler it will call the base class's copy constructor.
Compiler defined constructors are not special, they can be called explicitly:
class Base {
int num_
public:
Base(int n) : num_(n) { }
// copy constructor defined by compiler
};
class Derived : public Base {
float flt_;
public:
Derived(float f, int n) : Base(n), flt_(f) { }
// Copy constructor
Derived(const Derived& other)
: Base(other) // OK to explicitly call compiler generated copy constructor
, flt_(other.flt_)
{
}
};
For more details see this Wikipedia article.
If you don't specify a copy constructor the compiler generates one automatically. This constructor is generated in a way that it calls the copy constructor of the base class.
If you implement the copy constructor yourself, you also specify what base class constructor should be used (see Motti's answer). If you don't specify anything, the default constructor is used (That's why it is called "default constructor": it is used when no constructor is explicitly specified).
SO the compiler automatically generates a reasonable copy constructor, but if you want something special no further magic is going on and you have to specify yourself how that constructor exactly should look like.
class Base {
int num_
public:
Base(int n) : num_(n) { }
// copy constructor defined by compiler
};
class Derived : public Base {
float flt_;
public:
Derived(float f, int n) : Base(n), flt_(f) { }
// Copy constructor
Derived(const Derived& other)
: Base(other) // OK to explicitly call compiler generated copy constructor
, flt_(other.flt_)
{
}
};