Inherited constructor (using) and move - c++

UPDATE: it seems it's my fault, I didn't installed correctly CTP. MS weren't able to reproduce the bug.
I'd like to move a variable from a derived class to my base class (there are multiple classes between them)
Usually, I would pass the argument by const&, but I'm trying to pass it by value and move it down the hierarchy, avoiding a copy.
Here are my classes:
#include <string>
class base {
public:
explicit base(std::string url) : url_{std::move(url)} {}
// prevent copy
base(const base&) = delete;
base& operator=(const base&) = delete;
virtual ~base() {}
protected:
std::string url_;
};
class derived : public base {
public:
using base::base;
};
class derived_final : public derived {
public:
using derived::derived;
explicit derived_final(std::string url) :
derived{std::move(url)}
{
// do some stuff
}
};
int main() {
derived_final df { "test" };
}
and the log:
e:\project\test\main.cpp(25) : error C2664: 'derived::derived(const derived &)': cannot convert argument 1 from 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>' to 'const derived &'
Reason: cannot convert from 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>' to 'const derived'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
I also tried adding a move constructor to base, aswell as an op=.
But derived_final tries to use derived's copy constructor with std::string as parameter, when I try to move url to derived in derived_final's constructor.
Any ideas why this is happening?
I'm using msvc 2013 with CTP (for "using" support).
source here: https://bitbucket.org/syl/c-11-inherited-constructor-and-move/src

Seems to be a MSVC bug. GCC reports no errors.

Related

Would a derived class ever have an implicit copy constructor or assignment operator when it's deleted in the base class?

Qt defines Q_DISABLE_COPY as follows:
#define Q_DISABLE_COPY(Class) \
Class(const Class &) = delete;\
Class &operator=(const Class &) = delete;
Q_DISABLE_COPY is used in the QObject class, but the documentation for it says that it should be used in all of its subclasses as well:
when you create your own subclass of QObject (director or indirect), you should not give it a copy constructor or an assignment operator. However, it may not enough to simply omit them from your class, because, if you mistakenly write some code that requires a copy constructor or an assignment operator (it's easy to do), your compiler will thoughtfully create it for you. You must do more.
But consider this program:
struct Base {
Base() = default;
private:
Base(const Base &) = delete;
Base &operator=(const Base &) = delete;
};
struct Derived : Base {};
int main() {
Derived d1;
Derived d2(d1); // error: call to implicitly-deleted copy constructor of 'Derived'
Derived d3;
d3 = d1; // error: object of type 'Derived' cannot be assigned because its copy assignment operator is implicitly deleted
}
The errors from trying to compile that program seem to indicate that the compiler will not create copy constructors or assignment operators in derived classes when they're deleted in base classes. Is Qt's documentation just wrong about this, or is there some edge case when it would create them?
Related, but not a duplicate: Repeating Q_DISABLE_COPY in QObject derived classes. It gives reasons why it may be useful to use Q_DISABLE_COPY in a class even if it wouldn't be copyable anyway, but doesn't confirm that it never will in fact be copyable without it.
Since the base class copy constructor is deleted, the derived class has no way to know how to copy the base class object. This will disable any implicit copy constructors provided by the compiler.
From cppreference:
The implicitly-declared or defaulted copy constructor for class T is
defined as deleted if any of the following conditions are true:
T has direct
or virtual base class that cannot be copied (has deleted,
inaccessible, or ambiguous copy constructors)
T has direct or virtual
base class with a deleted or inaccessible destructor;
Inheriting Q_DISABLE_COPY can be useful when the user inherits from a class that deletes the default copy constructor, but provides their default implementation to override it.
struct Base {
Base() = default;
private:
Base(const Base &) = delete;
Base &operator=(const Base &) = delete;
};
struct Derived : Base {
Derived() = default;
Derived(const Derived&) : Derived() {}
Derived &operator=(const Derived&) {
return *this;
}
};
struct MoreDerived : Derived {};
int main() {
Derived d1;
Derived d2(d1); // Works fine!
Derived d3;
d3 = d1; // Works fine!
MoreDerived md1;
MoreDerived md2(md1); // Works fine!
MoreDerived md3;
md3 = md1; // Works fine!!
}
Edit: As #SR_ rightly states, in the above implementation of Derived, Base is not being copy constructed. I just wanted to illustrate the fact that it is easy to introduce an unintentional copy constructor when another class is modified in the inheritance hierarchy.
Prior to commit a2b38f6, QT_DISABLE_COPY was instead defined like this (credit to Swift - Friday Pie for pointing this out in a comment):
#define Q_DISABLE_COPY(Class) \
Class(const Class &) Q_DECL_EQ_DELETE;\
Class &operator=(const Class &) Q_DECL_EQ_DELETE;
And Q_DECL_EQ_DELETE like this:
#ifdef Q_COMPILER_DELETE_MEMBERS
# define Q_DECL_EQ_DELETE = delete
#else
# define Q_DECL_EQ_DELETE
#endif
Q_COMPILER_DELETE_MEMBERS got defined if C++11 support (or at least a new enough draft of it to support = delete) was available.
Thus, if you compiled Qt back then against a C++03 compiler, it would instead have compiled something like this:
struct Base {
Base() {};
private:
Base(const Base &);
Base &operator=(const Base &);
};
struct Derived : Base {};
int main() {
Derived d1;
Derived d2(d1);
Derived d3;
d3 = d1;
}
And compiling that with g++ -std=c++03 gives you these errors:
<source>: In copy constructor 'Derived::Derived(const Derived&)':
<source>:9:8: error: 'Base::Base(const Base&)' is private within this context
9 | struct Derived : Base {};
| ^~~~~~~
<source>:5:5: note: declared private here
5 | Base(const Base &);
| ^~~~
<source>: In function 'int main()':
<source>:13:18: note: synthesized method 'Derived::Derived(const Derived&)' first required here
13 | Derived d2(d1);
| ^
<source>: In member function 'Derived& Derived::operator=(const Derived&)':
<source>:9:8: error: 'Base& Base::operator=(const Base&)' is private within this context
9 | struct Derived : Base {};
| ^~~~~~~
<source>:6:11: note: declared private here
6 | Base &operator=(const Base &);
| ^~~~~~~~
<source>: In function 'int main()':
<source>:15:10: note: synthesized method 'Derived& Derived::operator=(const Derived&)' first required here
15 | d3 = d1;
| ^~
So back then, "your compiler will thoughtfully create it for you" was technically true but not practically so, since the compiler creating it would cause compilation to fail, just with a different (and arguably less clear) error. I'm now convinced that it's not true at all anymore now that = delete is unconditionally used, so I plan to ask Qt's maintainers to remove/reword that section of their documentation.

Inheritance, Copy Constructors and Implicit Typecasting

I have a derived class which I want to be able to construct using the copy constructor where the argument is an instance of the base class.
I am sure this should be possible in C++. Here is an example:
#include <string>
class Base
{
public:
friend
void swap(Base& l, Base& r)
{
using std::swap;
swap(l.a, r.a);
}
Base()
: a{1}
{
}
Base(const int a)
: a{a}
{
}
virtual
~Base()
{
}
Base(const Base& base)
: a{base.a}
{
}
Base(Base&& base)
: Base()
{
swap(*this, base);
}
Base& operator=(Base base)
{
swap(*this, base);
return *this;
}
protected:
int a;
};
class Derived : public Base
{
protected:
std::string b;
};
int main()
{
Base base(2);
Derived derived(base);
}
The error (g++ main.cpp) is:
main.cpp: In function ‘int main()’:
main.cpp:71:31: error: no matching function for call to ‘Derived::Derived(Base&)’
class Derived derived(base);
^
main.cpp:57:7: note: candidate: Derived::Derived()
class Derived : public Base
^~~~~~~
main.cpp:57:7: note: candidate expects 0 arguments, 1 provided
main.cpp:57:7: note: candidate: Derived::Derived(const Derived&)
main.cpp:57:7: note: no known conversion for argument 1 from ‘Base’ to ‘const Derived&’
main.cpp:57:7: note: candidate: Derived::Derived(Derived&&)
main.cpp:57:7: note: no known conversion for argument 1 from ‘Base’ to ‘Derived&&’
So the compiler doesn't know how to convert from an instance of Base to Derived implicitly.
I thought that this should be legal in C++. Do I require an explicit conversion statement?
What are you doing doesn't make much sense by itself because Base is not a sub-type of Derived so it can't be used as its replacement/substitution, however you could attempt to give it sense (same as with initialization from any other type) by writing a converting constructor:
class Derived : public Base
{
public:
Derived(const Base &bs) : Base(bs), b("constructed from base") {}
protected:
std::string b;
};
This would first initialize Derived Base part from bs and then init the string b with some value (though you can leave it out if you want it to be default-inited to empty string).
https://godbolt.org/z/GMELW_
Yes, you need to cast explicitely from Base to Derived. Every Mercedes is a car, but not every car is a Mercedes.
this statement Derived derived(base); or to simplify B b(A()); do an implicit conversion of type A to type B, which is legal only if class B inherit directly or indirectly from Class A.
Why ? Because class B could contains new information, in your case a string b, and a cast don't "append" information.
There is a simple way of solving this problem: By pulling the Base constructor into the scope of Derived.
This can be done with the using statement:
class Derived : public Base
{
public:
using Base::Base; // Pulls in the Base class constructors into the scope of Derived
...
};
I found what I was looking for (I couldn't remember the name so couldn't google it before). However this technique actually doesn't work due to the fact that I am using inheritance. (Or at least I don't know how to make it work.)
Type conversion operator:
Base::operator Derived()
{
Derived derived;
derived.a = a;
return derived;
}
This doesn't actually compile because the compiler doesn't know what Derived is. (Since Derived inherits from Base.) I don't know if it is possible to make this work by separating the compilation units.

gmock with base class constructor

I'm getting a compiler error, which I don't understand why. Or rather, I believe I'm doing what it telling me to. (Or not doing what I shouldn't do)
// InterfaceClass.h
class InterfaceClass {
public:
explicit InterfaceClass(DependencyClass * const p_dc);
};
// MockClass.h
class MockClass : public InterfaceClass {
public:
explicit MockClass(DependencyClass * const p_dc) : InterfaceClass(p_dc) {}
};
// test_MyTest.cpp
class MyTestFixture : public testing::Test {
protected:
MockDependencyClass mock_dependency;
NiceMock<mocks::MockClass> mock;
public:
MyTestFixture() : mock(&mock_depedency) {}
};
The error I'm getting when compiling my test is this:
In file included from test/test_MyTest.cpp:2:
In file included from vendor/googlemock/include/gmock/gmock.h:62:
vendor/googlemock/include/gmock/gmock-generated-nice-strict.h:92:12: error: constructor for 'testing::NiceMock<MockClass>' must explicitly initialize the base class 'InterfaceClass' which does not have a default constructor
explicit NiceMock(const A1& a1) : MockClass(a1) {
^
test/test_MyTest.cpp:43:30: note: in instantiation of function template specialization 'testing::NiceMock<MockClass>::NiceMock<DependencyClass *>' requested here
MyTestFixture(void) : mock(&mock_dependency) {
^
src/InterfaceClass:21:7: note: 'InterfaceClass' declared here
class InterfaceClass {
^
So, if I'm understanding this correctly, its telling me that my mock cannot initialise the interface class, because there is no default constructor and I haven't specified a non-default constructor to use. But I have? And if I understand gmock's source correctly, it supports constructors with up to 10 parameters.
And in my test fixture; if I make the mock a regular mock (i.e. not a NiceMock), it compiles.
What am I doing wrong here?

Unreasonably deleted move constructor

I have a class with explicitely deleted copy constructor named, let's say, NonCopyable. Then there's a class Base1 with a member of type NonCopyable. And another class Base2 with Base1 as parent. And finally - a Derivative class which parent is Base2.
Since NonCopyable is non-copyable, it's obvious that Base1, Base2 and Derivative will be also non-copyable. But it seems like there's been also move constructor (and assign operator) deleted.
Test it here:
GCC
MSVC
Following line gives those errors:
Derived d1, d2 = std::move(d1);
GCC: 'Derived::Derived(Derived&&)' is implicitly deleted because the default definition would be ill-formed:
class Derived :
the rest of errors just claims that Base1 and Base2 copy ctors are implicitly deleted which is not weird
MSVC: error C2280: 'Derived::Derived(const Derived &)': attempting to reference a deleted function
In provided links there's also commented lines which gives similar errors. Please uncomment them to see more errors I'd like to show you (e.g. with remove_if uncommented it complains about deleted move (on GCC) /copy (on MSVC) assign operator).
What I want to achieve is make Derivative (and its bases also) moveable, but not copyable.
I'm working with Visual Studio 2015 and getting exactly the same error as in the msvc link I provided, but I'm not sure what version of MSVC is used to compile on rextester.com.
I'm pasting the code also here at the request of #Richard Critten:
class NonCopyable
{
public:
NonCopyable() { }
NonCopyable(const NonCopyable &) = delete;
NonCopyable & operator=(const NonCopyable &) = delete;
NonCopyable(NonCopyable &&) { }
NonCopyable & operator=(NonCopyable &&) { return *this; }
};
class Base1
{
public:
virtual ~Base1() = default;
private:
NonCopyable m;
};
class Base2 :
public Base1
{
public:
virtual ~Base2() = default;
};
class Derived :
public Base2
{
};
int main()
{
std::vector<Derived> v;
//std::remove_if(v.begin(), v.end(), [](const Derived &) { return true; });
//v.emplace_back();
Derived d1, d2 = std::move(d1);
}
[class.copy]/9 If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if
(9.4) — X does not have a user-declared destructor.
Base1 has a user-declared destructor, so no move constructor for it. And copy constructor is implicitly declared as deleted due to non-copyable member. So Base1 can be neither copied nor moved, and of course Base2 and Derived together with it.

Creating a derived class from a base

I get the following error message:
conversion from ‘BaseClass’ to non-scalar type ‘DerivedClass’ requested
while compiling something like:
AnotherClass response;
DerivedClass message = response.serialize(QString("someStuff"));
where I have
BaseClass AnotherClass::serialize( const QString& valueName ) const
and
class DerivedClass : public BaseClass
{
...
DerivedClass &operator=(const BaseClass &other);
}
Can someone explain what is wrong here, and more importantly why?
DerivedClass message = response.serialize(QString("someStuff"));
This is copy-initialization, not assignment, and operator= doesn't even come in play.
You either need a constructor that takes BaseClass or write it like this:
AnotherClass response;
DerivedClass message;
message = response.serialize(QString("someStuff")); // assignment
Besides using copy-initialization, not assignment as you think you are, you are also violating the rule of three/four.
The rule is that if you have any of the below, you must have all of them (either implemented or deleted using Q_DECL_EQ_DELETE):
Destructor
Copy Constructor
Move Constructor (for C++11)
Assignment Operator
For example, suppose you don't want to implement assignment. You should have:
class MyClass {
// private, deleted - compatible with both C++11 and C++98/03.
MyClass & operator=(const MyClass &) Q_DECL_EQ_DELETE;
public:
MyClass(const MyClass &);
MyClass(MyClass &&);
virtual ~MyClass();
...
};