The following code:
#include <iostream>
#include <string>
using namespace std;
void print(string a) { cout << a << endl; }
void print(string a, string b) { cout << a << b << endl; }
class A {
public:
string p;
A() { print("default constructor"); }
A(string a){ p = a; print("string constructor ", p); }
A(const A& o) { print("copy constructor"); }
A (A&& o) { print("move constructor"); }
A& operator=(const A& o) { print("copy assignment"); return *this; }
A& operator=(const A&& o) { cout << "move assignment to:" << p << " from:" << o.p << endl; return *this; }
~A() { print("destructor ", p); }
};
A operator+(const A& a, const A& b) {
cout << "add" <<endl;
A c("f");
return c;
}
A f(A& a, A& b, A& c) {
A d("e");
d = a+b+c;
print("after add");
return d;
}
int main() {
A a("a"); A b("b"); A c("c");
A whereDidThisGo {f(a,b,c)};
print("end");
}
has the following output:
string constructor a
string constructor b
string constructor c
string constructor e
add
string constructor f
add
string constructor f
move assignment to:e from:f
destructor f
destructor f
after add
end
destructor e
destructor c
destructor b
destructor a
Process exited after 0.06744 seconds with return value 0
Press any key to continue . . .
Where is the construction/destruction of the whereDidThisGo variable defined in main?
Where is the construction/destruction of the whereDidThisGo variable defined in main?
You do not see the ouptut for this due to named return value optimization(aka NRVO).
it's not a good optimization for people like me who are trying to learn constructors
You can disable this NRVO by providing the -fno-elide-constructors flag to the compiler. Demo.
Also, note that in your example the A::operator=(const A&&) should instead be:
//-----------vv------->no need for const here
A::operator=(A&&)
TIL about NRVO, it's not a good optimization for people like me who are trying to learn constructors haha.
Thank you for the answers, yes the move assignment should be a non-const pointer, I simply overlooked it.
Related
I want to make an operator= and copy constructor, to be called in the inherited class.
For normal objects, it works fine, but when I'm trying to call, for example, operator= with a pointer, it is just copying the object address.
So my question is, how can I call those methods with pointers?
#include <iostream>
// base class
class a {
public:
//constructors
a(): x(0), y(1), z(0){ std::cout << "no parameter constructor A\n"; }
a(int a, int b, int c) :x(a), y(b), z(c){ std::cout << "parameter constructor A\n"; }
a(const a& ob):x(ob.x), y(ob.y), z(ob.z)
{
std::cout << "copy constructor A\n";
}
//operator
a& operator=(const a& obj)
{
if (this != &obj)
{
x = obj.x;
y = obj.y;
z = obj.z;
}
std::cout << "operator = A\n";
return *this;
}
protected:
int x, y, z;
};
//child class
class b : public a
{
public:
//constructors
b() : p(0){ std::cout << "no parameter constructor B\n"; }
b(int X, int Y, int Z, int B) : a(X, Y, Z), p(B) { std::cout << "parameter constructor B\n"; }
b(const b& obj) :p(obj.p), a(obj)
{
std::cout << "copy constructor B\n";
}
//operator =
b& operator=(const b &obj)
{
if (this != &obj)
{
p = obj.p;
&a::operator=(obj);
}
std::cout << "operator = B\n";
return *this;
}
private:
int p;
};
int main()
{
b obj0(4, 8, 16, 32);
b obj1(obj0); // copy constructor
b obj2;
obj2 = obj1; // operator =
std::cout << std::endl << std::endl;
std::cout << "for pointers:\n\n";
a* obj3 = new b(4, 8, 16, 32);
a* obj4(obj3);
obj4 = obj3;
return 0;
}
One of the purposes of using pointers (or references) is to avoid needing to create a copy of the object. Passing a pointer to the object allows the receiver to refer to and manipulate on the original object.
If you wish the pointer to receive a new object, then you would use new.
When dealing with polymorphism as in your example, you would probably need a virtual method that creates a proper clone (sometimes called a deep copy).
class a {
//...
virtual a * clone () const = 0;
};
class b : public a {
//...
b * clone () const {
return new b(*this);
}
};
//...
a *obj4 = obj3->clone();
//...
We leverage that b * is a covariant return type for a *, so that b::clone() can return a b *, but a::clone() can use the b::clone() as an override and still return an a *.
At the last line myA = foo(myOtherB);, the function will return type an object of type A, thus; it will be like saying `myA = input, But why is the copy constructor is being?
output:
B foo()
A copy ctor //what calls this?
A op=
For a copy constructor to be called we will have to use the assignment operator during initialization such as: B newB = myOtherB;
#include <iostream>
using namespace std;
class A {
public:
A() { cout << "A ctor" << endl; }
A(const A& a) { cout << "A copy ctor" << endl; }
virtual ~A() { cout << "A dtor" << endl; }
virtual void foo() { cout << "A foo()" << endl; }
virtual A& operator=(const A& rhs) { cout << "A op=" << endl; }
};
class B : public A {
public:
B() { cout << "B ctor" << endl; }
virtual ~B() { cout << "B dtor" << endl; }
virtual void foo() { cout << "B foo()" << endl; }
protected:
A mInstanceOfA; // don't forget about me!
};
A foo(A& input) {
input.foo();
return input;
}
int main() {
B myB;
B myOtherB;
A myA;
myOtherB = myB;
myA = foo(myOtherB);
}
At the last line myA = foo(myOtherB);, the function will return type an object of type B
Not true. Your function returns an object of type A by value. That means, any value you feed this object to be constructed with will be used to construct a new object of that exact type. So in other words:
int foo(float a) {
return a + 0.5;
}
int u;
u = foo(9.3);
// u has a value of 10
Don't expect u to hold a value that a int cannot.
Same thing if you use user defined types:
A foo(A& input) {
input.foo();
return input; // this expression returns a new A
// using the value of `input`
}
A myA;
myA = foo(myOtherB);
// why would `myA` be anything else than the value of an A?
So then, what happen here?
B foo()
A copy ctor //what calls this?
A op=
A foo(A& input) {
input.foo(); // prints B foo, virtual call. a reference to A that
// points to an object of subclass type B
return input; // copy `input` into the return value object
}
Then, the operator= gets called.
See cppreference
Specifically:
The copy constructor is called whenever an object is initialized (by direct-initialization or copy-initialization) from another object of the same type (unless overload resolution selects a better match or the call is elided), which includes
initialization: T a = b; or T a(b);, where b is of type T;
function argument passing: f(a);, where a is of type T and f is void f(T t);
function return: return a; inside a function such as T f(), where a is of type T, which has no move constructor.
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).
#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.
In the code show below, how do I assign rvalue to an object A in function main?
#include <iostream>
using namespace std;
class A
{
public:
int* x;
A(int arg) : x(new int(arg)) { cout << "ctor" << endl;}
A(const A& RVal) {
x = new int(*RVal.x);
cout << "copy ctor" << endl;
}
A(A&& RVal) {
this->x = new int(*RVal.x);
cout << "move ctor" << endl;
}
~A()
{
delete x;
}
};
int main()
{
A a(8);
A b = a;
A&& c = A(4); // it does not call move ctor? why?
cin.ignore();
return 0;
}
Thanks.
Any named instance is l-value.
Examples of code with move constructor:
void foo(A&& value)
{
A b(std::move(value)); //move ctr
}
int main()
{
A c(5); // ctor
A cc(std::move(c)); // move ctor
foo(A(4));
}