Cpp Operator = between 2 classes - c++

I have a surprising issue in VS2010.
This is the header.h of my main.cpp
class A;
class B;
class A
{
public:
double x,y;
A();
~A();
A(const A &obj);
A(const B &obj);
A& operator=(const A &obj);
};
class B
{
public:
double x,y;
B();
~B();
B(const B &obj);
B& operator=(const B &obj);
};
The main.cpp is containing the declaration of methods and :
#include "header.h"
#include <iostream>
int main() {
A t;
B u;
A a(u);
t=u;
return 0;
}
As you can see, to do
A a(u);
I had to add this method
A(const B &obj);
But for
t=u;
It uses
A& operator=(const A &obj);
Why I don't get an error ?

If you want to avoid this, you should mark your "A from B" constructor as explicit:
explicit A(const B &obj);
Any constructor not marked as explicit will be used by the compiler for implicit conversions.

by adding A(const B &obj); you provided a way to convert B to A, which is used in t=u; so the compiler can do what you ask and no error is needed. The conversion can be done because the parameter const A &obj allows conversion.

If, for whatever reason, the A(const B &obj) is meaninful but you also want t=u to fail then you have to disable implicit type conversion using the explicit keyword.
This means that only when you specifically cast B as an instance of A will the conversion be performed.

Related

Is the assignment operator inherited or not?

I know that the assignment operator is not inherited by derived classes, instead the compiler will create a default one if it is not redeclared. But I do not understand why the output of the following code snippet is Base operator=:
#include <iostream>
using namespace std;
class B {
protected:
int h;
public:
B& operator=(const B& ob){
if (this!=&ob) {
h = ob.h;
cout << "Base operator=\n";
}
return *this;
}
};
class D: public B {
protected:
float r;
public:
};
int main() {
D a, b;
a = b;
return 0;
}
Doesn't that mean that when calling a = b the base B& operator=(const B& ob, so isn't it inherited? Where am I wrong ?
The generated assignment is "all the base assignments, in order of inheritance declaration", so your generated assignment is essentially
D& operator=(const D& d)
{
B::operator=(d);
return *this;
}
If you were to derive from both B and C - in that order; class D: B, C - it would be equivalent to
D& operator=(const D& d)
{
B::operator=(d);
C::operator=(d);
return *this;
}
That is, the assignment is not inherited, but it's used.
With the expression a = b, the compiler generated assignment operator for D calls the user-defined assignment operator in B.
Yes you are correct that assignment operators are not inherited.

Delegating to a default C++ constructor

Assume a C++ class A with members that can all be copied by the their respective copy constructors. We can rely on the default copy constructor for A to copy its members:
class A {
private:
A(const A&) = default; // We don't really need this line
int a;
B b;
double c;
}
But now let's assume that I want to "extend" (or annotate) the default constructor of A so that in addition to copying its members, it does something else, e.g. writes a line to a log file.
I.e. I'd like to write something like:
class A {
public:
A(const A& a) : A::default(A) {
print("Constructing A\n");
}
private:
// like before
}
Unfortunately that is not correct C++ syntax.
So is there a syntax which allows delegating to a default C++ constructor while explicitly defining the same constructor?
The simplest is to move all members into a base class and write the message in a derived class:
class A_helper {
private:
int a;
B b;
double c;
};
class A : public A_helper {
public:
A() = default;
A(const A& a) : A_helper(a) {
print("Constructing A\n");
}
A(A&& a) : A_helper(std::move(a)) {
print("Constructing A\n");
}
};
You can delegate to the default constructor like you would default-initialize a member variable:
A(const A&) : A()
{
...
}
As often, "We can solve any problem by introducing an extra level of indirection." ( "…except for the problem of too many levels of indirection,"):
struct VerboseA
{
VerboseA() = default;
VerboseA(const VerboseA&) { print("Constructing A\n"); }
VerboseA(VerboseA&&) { print("Constructing A\n"); }
};
And then
class A : VerboseA // EBO (Empty Base Optimisation)
{
private:
A(const A&) = default; // We don't really need this line
int a;
B b;
double c;
};
or in C++20
class A {
private:
A(const A&) = default; // We don't really need this line
[[no_unique_address]]VerboseA verbose; // "EBO" equivalent with attribute
int a;
B b;
double c;
};

why use of deleted rvalue reference constructor function?

This is a very simple example with class A and B.
I want allow only deep copy, so I disabled the rvalue reference constructor.
#include <iostream>
class B;
class A {
public:
A();
~A();
A(const A & other);
A& operator=(const A & other);
A(A && ) = delete;
A& operator=(A && ) = delete;
B toB() const;
private:
int a_;
};
class B {
public:
B();
~B();
B(const B & other);
B& operator=(const B & other);
B(B && ) = delete;
B& operator=(B && ) = delete;
A toA() const;
private:
int b_;
};
A::A()
{
}
A::~A()
{
}
A::A(const A & other)
: a_(other.a_)
{
}
A& A::operator=(const A & other)
{
a_ = other.a_;
return *this;
}
B A::toB() const
{
return B();
}
B::B()
{
}
B::~B()
{
}
B::B(const B & other)
: b_(other.b_)
{
}
B& B::operator=(const B & other)
{
b_ = other.b_;
return *this;
}
A B::toA() const
{
return A();
}
int main()
{
A a();
B b();
return 0;
}
the gcc compiler report bugs like this:
In member function 'B A::toB() const':
error: use of deleted function 'B::B(B&&)'
return B();
^
note: declared here
B(B && ) = delete;
I'm wandering why it use B(B && ) function, not the B(const B &) function instead.
Because you added the move-constructor. Deleted but declared functions are still part of the interface of a class. That means it will be considered by the compiler, but since it's marked as deleted you get the error. If you want to force the copy-constructor to be called then remove the move-constructor declaration.
From this deleted functions reference:
Any use of a deleted function is ill-formed (the program will not compile). This includes calls, both explicit (with a function call operator) and implicit (a call to deleted overloaded operator, special member function, ...
[Emphasis mine]
Since the deleted functions are part of the interface, the compiler will try to use them. So when there is a deleted move constructor, the compiler will see that and try to use it, but since it is deleted there will be an error.
Since no move constructor will be created by the compiler if there is an explicit copy constructor (as per this move constructor reference) simply having a defaulted copy constructor will inhibit moving of object.
All of that means your classes can be very much simplified:
class A {
public:
A() : a_() {}
A(const A & other) = default;
B toB() const;
private:
int a_;
};
class B {
public:
B() : b_() {}
B(const B & other) = default;
A toA() const;
private:
int b_;
};
Because the classes above have user-declared copy constructors no movement constructor will be created, and the class can't be moved only copied.
Move Constructor would be called whenever a nameless object is created.
In B A::toB() const function there is a statement return B(); which creates a nameless object to be returned from the function. For creating a nameless object move constructor is required which is deleted.

Simple copy constructor in C++

Let's say we have two classes in C++:
Class A{
public:
A();
private:
int k;
};
Class B{
public:
B();
private:
A a;
};
I edit my question such that it is more helpful for anyone does reach it someday.
How could I write the copy ctor of B (is it a copy ctor indeed?) for initializing a (which is of type Class A) with another object instance of A (let it be a_inst) which have already been defined and initialized before?
In other words, what would be the code for the ctor B()?
I would do it like this
B(const A &paramA) : a(paramA) {}
B(A &&paramA) : a(move(paramA)) {}
B(const B &src) : a(src.a) {}
Beside the copy constructor I am also proposing two additional constructors, one that can be initialized by l-value instances of A and other for r-value instances. Depending on the semantics of A you may not need the move version.
Class A{
public:
A();
A(const A& obj);
private:
int k;
};
Class B{
public:
B();
B(const B& obj)
: a(obj.a) { }
B(const A& obj)
: a(obj) { }
private:
A a;
};

Add a conversion constructor without touching class

I have two classes, from two different libraries, with the same meaning:
class A {
public:
A() {}
A(const A&) {}
};
class B {
public:
B() {}
B(const B&) {}
};
I want to call functions with B as parameter, passing an A object:
void setB(const B&) {
}
int main(int argc, char* argv[]) {
A a;
setB(a);
}
I know this is possible, adding a conversion contructor from:
class B {
public:
B() {}
B(const B&) {}
B(const A&) {} // CANNOT ADD THIS!
};
But these classes are defined in two external libraries and I haven't rights to change them.
How can I add a conversion constructor (or achieve the same result) without touching the B class definition?
How can I add a conversion constructor (or achieve the same result) without touching the B class?definition?
If the B class has a virtual destructor, you can specialize B and add the extra functionality in the specialization. If it does not have a virtual destructor, you can embed B in a wrapper class.
That means either:
class SpecialB: public B { // if B has virtual destructor
public:
SpecialB(const A&); // you _can_ do this
};
or:
class SpecialB {
public:
SpecialB(const A&); // you _can_ do this
private:
B wrapped_b;
};
Just use a factory:
struct AfromB
{
static A convert(const B&);
}
and:
setB(AfromB::convert(a));
If you have no access to B class definition, maybe the simpler is to have a void setB(const A&) overload.