I want to inherit copy constructor of the base class using using keyword:
#include <iostream>
struct A
{
A() = default;
A(const A &) { std::cerr << __PRETTY_FUNCTION__ << std::endl; }
A( A &&) { std::cerr << __PRETTY_FUNCTION__ << std::endl; }
A& operator=(const A &) { std::cerr << __PRETTY_FUNCTION__ << std::endl; return *this; }
A& operator=( A &&) { std::cerr << __PRETTY_FUNCTION__ << std::endl; return *this; }
};
struct B : A
{
using A::A;
using A::operator=;
B& operator=(const B &) { std::cerr << __PRETTY_FUNCTION__ << std::endl; return *this; }
B& operator=( B &&) { std::cerr << __PRETTY_FUNCTION__ << std::endl; return *this; }
};
int main()
{
A a;
B b;
b = a; // OK
B b1( a ); // compile error
B b2(std::move(a)); // compile error
return 0;
}
Inheriting assignment operator using using keyword works OK, but inheriting copy and move constructors causes a compilation error: an inherited constructor is not a candidate for initialization from an expression of the same or derived type.
http://coliru.stacked-crooked.com/a/fe84b429c391c894:
main.cpp:16:14: note: an inherited constructor is not a candidate for initialization from an expression of the same or derived type
main.cpp:8:5: note: candidate: A::A(A&&)
A( A &&) { std::cerr << __PRETTY_FUNCTION__ << std::endl; }
^
main.cpp:16:14: note: inherited here
using A::A;
Why can I inherit assignment operator but cannot inherit copy constructor? What is a difference? I could understand if I couldn't inherit assignment operators too. But inheriting assignment operators in contrary is considered OK. That is a little strange for me.
The story
What I want is similar to what is asked in this question: I want to just add new methods to existing class without modifying it (it's a class from another library).
http://coliru.stacked-crooked.com/a/149a6194717cd465:
#include <iostream>
struct A // not my class
{
};
struct B : A
{
using A::A;
using A::operator=;
void foo() { std::cerr << "fuu" << std::endl; }
};
A NotMyFunc()
{
return {};
}
int main()
{
B b(NotMyFunc());
b.foo();
return 0;
}
But I don't want to reimplement copy and move constructors.
You need a constructor for B that has A as parameter. Then you need to make the default constructor explicit.
struct B : A
{
using A::A;
using A::operator=;
B() = default;
B(const A& a) : A(a) {}
B(A &&a): A(std::move(a)) {}
};
Related
I have two similar pieces of code. The first version unexpectedly calls the default constructor while the second doesn't. They both call the move operator / move constructor, respectively, as expected.
class MyResource
{
public:
MyResource() : m_data(0) { std::cout << "Default Ctor" << std::endl; }
MyResource(int data) : m_data(data) { std::cout << "Int Ctor" << std::endl; }
MyResource(MyResource const& other) = delete;
MyResource& operator=(MyResource const& other) = delete;
MyResource(MyResource&& other) noexcept : m_data(other.m_data) { std::cout << "Move Ctor" << std::endl; }
MyResource& operator=(MyResource&& other) noexcept { std::cout << "Move Op" << std::endl; m_data = other.m_data; return *this; }
~MyResource() { std::cout << "Dtor" << std::endl; }
private:
int m_data = 0;
};
class MyWrapper
{
public:
MyWrapper(MyResource&& resource)
// : m_resource(std::move(resource)) // Version 2
{
// m_resource = std::move(resource); // Version 1
}
private:
MyResource m_resource;
};
My test usage is:
MyWrapper* wrapper = new MyWrapper(MyResource(1));
delete wrapper;
With Version 1, I get:
Int Ctor
Default Ctor
Move Op
Dtor
Dtor
While Version 2 outputs:
Int Ctor
Move Ctor
Dtor
Dtor
What's the reason behind this difference?
Why does version 1 call the default constructor?
Members are initialized before the construct body runs. A much simpler example to see the same:
#include <iostream>
struct foo {
foo(int) { std::cout << "ctr\n";}
foo() { std::cout << "default ctr\n";}
void operator=(const foo&) { std::cout << "assignment\n"; }
};
struct bar {
foo f;
bar(int) : f(1) {}
bar() {
f = foo();
}
};
int main() {
bar b;
std::cout << "---------\n";
bar c(1);
}
Output:
default ctr
default ctr
assignment
---------
ctr
You cannot initialize a member in the body of the constructor! If you do not provide an initializer, either in the member initializer list or as an in class initializer, then f is default constructed. In the constructor body you can only assign to an already initialized member.
I would like to ask about casting in C++.
I heard that when casting is ambiguous compiler should return an error,
but, just for better understanding, I tested it and it didn't, moreover, it used functions in quite weird order. When:
A foo;
B bar = foo;
it used casting operator, but when I typed:
bar = static_cast<B>(foo);
it used single argument constructor.
Can anyone explain why it acts in this way?
The whole code which I used:
#include <iostream>
#include <typeinfo>
using namespace std;
class B;
class A {
public:
A() {}
A (const B& x);
A& operator= (const B& x);
operator B();
};
class B {
public:
B() {}
B (const A& x) {
cout << "constructor B" << endl;
}
B& operator= (const A& x) {
cout << "Assign B" << endl;
return *this;
}
operator A() {
cout << "Outer B" << endl;
return A();
}
};
A::A (const B& x) {
cout << "constructor A" << endl;
}
A& A::operator= (const B& x) {
cout << "Assign A" << endl;
return *this;
}
A::operator B() {
cout << "Outer A" << endl;
return B();
}
int main ()
{
A foo;
// First one
B bar = foo;
bar = foo;
foo = bar;
// Second one
bar = static_cast<B>(foo);
B bar2 = static_cast<B>(foo);
foo = static_cast<A>(bar);
B bar3 = foo;
A foo2 = bar3;
A foo3 = B();
foo3 = B();
return 0;
}
Edit:
My output:
Outer A
Assign B
Assign A
Copy constructor B
Copy constructor B
Copy constructor A
Outer A
Outer B
Outer B
Assign A
The reason your compiler does not complain about ambiguity is that your constructors and assignment operators take a const A/B&, but operator A() and operator B() are not declared const. For the conversion of non-const objects, the compiler therefore prefers operator A/B().
I think that the rest can be explained with the rules of static_cast conversion, which in your code amounts to behavior as in direct initialization, and overload resolution (which is why the assignment operator is only called in the last example).
I have a class A
struct A{
A(){}
A(int x): d(x) {}
A(const A& a): d(a.d) {
std::cout << "copy construction" << std::endl;
}
A(A&& a): d(a.d){
std::cout << "move construction" << std::endl;
}
A& operator=(const A& a){
std::cout << "copy assignment" << std::endl;
d = a.d;
return *this;
}
A& operator=(A&& a){
std::cout << "move assignment" << std::endl;
d = a.d;
return *this;
}
int d;
};
and a function func
A func(){
return A(3);
}
if I do this
A x;
x = func();
the output is "move assignment" as expected
but if I construct A like this
A x = func();
then nothing is printed as if c++ generates its own move constructor and refuses to use the defined one.
I'm using visual studio 14
I'd really like to understand this.
Thank you for explanations.
The constructor call is elided.
With gcc, you can disable it with -fno-elide-constructors.
msvc doesn't have equivalent option.
I have this couple of code-lines:
#include <iostream>
using namespace std;
class A
{
public:
A() noexcept
{
cout << "A::A()" << endl;
}
A(const A&) noexcept
{
cout << "A::A(const A&)" << endl;
}
A(A&&) noexcept
{
cout << "A::A(A&&)" << endl;
}
};
class B
{
public:
B(const A& a) noexcept :
_a(a)
{}
B(A&& a) noexcept :
_a(a)
{}
private:
A _a;
};
int main(int argc, char* argv[])
{
A a;
B b1 = B(a);
B b2 = B(A());
}
They produce this output:
A::A()
A::A(const A&)
A::A()
A::A(const A&)
What need I to do in order to the A::A(A&&) will be called from the B::B(A&&)?
As you can see adding noexcept does not solve this issue.
Although the type of a is an rvalue reference to A, a itself is an lvalue. To retain its rvalue-ness, you need to use std::move:
B(A&& a) noexcept :
_a(std::move(a))
{}
#include <iostream>
using namespace std;
struct A
{
A() {}
A(const A &a) {
cout << "copy constructor" << endl;
}
A& operator=(const A &a) {
cout << "assigment operator" << endl;
}
A(A &&a) {
cout << "move" << endl;
}
A& operator=(A &&a) {
cout << "move" << endl;
}
};
struct B {
A a;
};
B func() {
B b;
return b;
}
int main() {
B b = func();
}
This prints "copy constructor".
For class B the move constructor and the move assignment operator should be automatic generated correct? But why is it using the copy constructor of class A and not the move constructor?
For me it doesn't print anything at all because the copy/move has been elided. However if I thwart RVO with something like:
extern bool choice;
B func() {
B b1, b2;
if (choice)
return b1;
return b2;
}
Then it prints:
move
It may be that your compiler does not yet implement the automatic generation of the move members.