How to understanding the meaning of C++03 13.5.3/2 - c++

#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
struct B {
virtual int operator= (int rhs)
{
m_iValue = rhs;
return m_iValue;
}
virtual B& operator= (const B& rhs)
{
m_iValue = rhs.m_iValue;
return *this;
}
int m_iValue;
};
struct D : B {
virtual int operator= (int rhs)
{
m_iValue = rhs;
return m_iValue;
}
virtual D& operator= (const B& rhs)
{
m_iValue = rhs.m_iValue;
return *this;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
D dobj1;
D dobj2;
B* bptr = &dobj1;
bptr->operator=(99); // calls D::operator=(int)
*bptr = 99; // ditto
bptr->operator=(dobj2); // calls D::operator=(const B&)
*bptr = dobj2; // ditto
dobj1 = dobj2; // calls implicitly-declared
// D::operator=(const D&)
return 0;
}
Question 1> This question maybe is related to the question 2&3.
Reference: C++03 13.5.3/2
Note: for a derived class D with a base class B for which a virtual
copy assignment has been declared, the copy assignment operator in D
does not override B’s virtual copy assignment operator.
What does the following statement mean in plain English?
the copy assignment operator in D does not override B’s virtual copy
assignment operator.
Question 2> why the following statement call `D::operator=(int)
*bptr = 99; // ditto
Question 3> Why the following statement call implicit D::operator=(const D&)
dobj1 = dobj2; // calls implicitly D::operator=(const D&)

Question 1.
For B, the copy assignment operator is B::operator=(const B&) or similar. For D it's D::operator=(const D&). One cannot override the other because argument types are different.

Related

implicit type conversion in C++ using overloaded =

in the below code (which is an example for type conversion):
// implicit conversion of classes:
#include <iostream>
using namespace std;
class A {};
class B {
public:
// conversion from A (constructor):
B (const A& x) {}
// conversion from A (assignment):
B& operator= (const A& x) {return *this;}
// conversion to A (type-cast operator)
operator A() {return A();}
};
int main ()
{
A foo;
B bar = foo; // calls constructor
bar = foo; // calls assignment
foo = bar; // calls type-cast operator
return 0;
}
in line 21:
bar = foo; // calls assignment
it calls the overloaded operator =. and in the body of class overloading for "=" operator is written in line 12:
B& operator= (const A& x) {return *this;}
it's statement says "return this". here this points to bar. and there's just a parameter of type class A:
const A& x
what does this function do with this parameter?
and in line 21 what is converted to what by writing:
bar = foo; ?
The real question you might be asking is what does the operator= function used for?
Normally we take some data from the constant reference
For example
struct A{
std::string data;
}
struct B{
std::string differentData;
B& operator=(const A& other){
differentData = other.data;
return *this;
}
}
Then if we call code like
int main(){
A a;
a.data = "hello";
B b;
b = a;
std::cout << b.differentData;
}
We should get "hello" printing to the console
Since you're not interacting with the class given in the function, all this code is doing is running an empty function.
The return is only used if you chain together equal calls
int main(){
B b1, b2, b3;
b3.differentData = "hi";
b1 = b2 = b3;
//Pushes hi from b3 >> b2 and returns b2
//Pushes hi from b2 >> b1 and returns b1
}
what does this function do with this parameter?
Nothing.
what is converted to what by writing: bar = foo;
Nothing. Or equivalently, the state of bar is replaced from the state of foo.

Clearing a class instance with a member that has a deleted assignment operator

I wanted to clear / reinstansiate a instance of a class using the assignment operator, but some members in that class have their assignment operator deleted. So when i try to assign it to a new instance it keeps its old values.
Heres a example:
#include <cstdio>
class C
{
C operator= (const C&) = delete;
};
class B
{
public:
int x = 0;
C c;
B& operator=(const B& other)
{
return B();
}
};
int main()
{
B b;
b.x = 5;
b = B();
printf("%i\n", b.x); // prints 5, should print 0
return 0;
}
Is there some simple workaround for this without writing a method that clears all of its members? Why does this happen?
Why does this happen?
Your current implementation of operator=() is fubar.
B& operator=(B const &other)
{
x = other.x;
return *this;
}
you should also test for self-assignment, before you do anything, though, since copying members can be quite expensive:
B& operator=(B const &other)
{
if(this != &other)
x = other.x;
return *this;
}

How to override operator+ in subclass

I have CharRow class with such fields :
protected:
char* ptr;
int ROW_MAX_LENGTH;
And have subclass BigIntegerNumber (char array of numbers).
My operator+ in CharRow :
virtual CharRow operator+ (CharRow row2)
{
int row1Length = this->getRowCurrentLength();
int row2Length = row2.getRowCurrentLength();
CharRow tempRow(row1Length + row2Length);
for(int i = 0; i < row1Length; i++){
tempRow.ptr[i] = this->ptr[i];
}
for(int i = 0; i < row2Length; i++){
tempRow.ptr[i + row1Length] = row2.ptr[i];
}
return tempRow;
}
What do I need to invoke operator+ polymorphically ?
BigIntegerNumber operator+ (BigIntegerNumber row2)
{
BigIntegerNumber temp(this->getRowCurrentLength() + row2.getRowCurrentLength());
temp = BigIntegerNumber::addValue(*this, row2);
return temp;
}
Virtual operator + can work in general, however for it to work, some constraints must be met.
The first reason why it would not work in your case is, that the operator
BigIntegerNumber operator+ (BigIntegerNumber row2)
is not an override of the
virtual CharRow operator+ (CharRow row2)
but it is its overload (hides the original operator instead of overriding it).
For it to be the override, the function signatures would have to be the same. I.e. the same types of parameters (CharRow and not BigIntegerNumber, also better to pass by const ref than by value), and the same or covariant return type. Neither of those are met.
Things like this are sometimes done by using a "regular" virtual function taking interface references as parameters, and implementing non-virtual operators by calling such func.
In this case the main issue is the return parameter, as you cannot define the return type as by-value CharRow and actually return BigIntegerNumber (it would be sliced to the return type). You might be more lucky with the operator +=, which can return the reference to itself thus be able to work polymorphically.
The example for operator += (which does not have the problem with the return value type):
#include <iostream>
using namespace std;
struct Base
{
virtual Base& operator +=(const Base& other); // takes Derived as well for the virtual calls
};
struct Derived: Base
{
Derived& operator +=(const Base& other); // override - called via virtual
Derived& operator +=(const Derived& other); // overload - not called via virtual
// remove to always call the polymorphic version
};
Base& Base::operator +=(const Base& other)
{
cout << "Base::operator +=(Base)";
// beware this is slow!
const Derived* d = dynamic_cast<const Derived*>(&other);
if (d)
cout << " - called with Derived";
else
cout << " - called with Base";
cout << endl;
return *this;
}
Derived& Derived::operator +=(const Base& other)
{
cout << "Derived::operator +=(Base)";
// beware this is slow!
const Derived* d = dynamic_cast<const Derived*>(&other);
if (d)
cout << " - called with Derived";
else
cout << " - called with Base";
cout << endl;
return *this;
}
Derived& Derived::operator +=(const Derived& other)
{
cout << "Derived::operator +=(Derived)" << endl;
return *this;
}
int main()
{
Derived d1, d2;
Base b, b0;
Base& b1 = d1;
Base& b2 = d2;
d1 += d2; // Derived::operator +=(Derived)
b1 += d2; // Derived::operator +=(Base) - called with Derived
d1 += b1; // Derived::operator +=(Base) - called with Derived
b1 += b2; // Derived::operator +=(Base) - called with Derived
b += d2; // Base::operator +=(Base) - called with Derived
d1 += b; // Derived::operator +=(Base) - called with Base
b += b0; // Base::operator +=(Base) - called with Base
b1 += b; // Derived::operator +=(Base) - called with Base
return 0;
}
For the operator + the result type passed by value is the problem. However, in C++ still not impossible, but you then need to use some kind of wrapper. An example of such a wrapper:
#include <iostream>
#include <memory>
using namespace std;
struct Base;
struct Derived;
class BaseWrapper
{
shared_ptr<Base> _obj;
public:
explicit BaseWrapper(const shared_ptr<Base>& obj) : _obj(obj)
{}
template<class RESULT_T>
operator RESULT_T()
{
// throws if type not correct
return dynamic_cast<RESULT_T&>(*_obj);
}
Base& operator +=(const Base& other);
BaseWrapper operator +(const Base& other) const;
};
struct Base
{
virtual Base& operator +=(const Base& other); // takes Derived as well for the virtual calls
BaseWrapper operator +(const Base& other) const;
private:
virtual shared_ptr<Base> copy() const
{
return make_shared<Base>(*this);
}
};
struct Derived : Base
{
Derived& operator +=(const Base& other); // override - called via virtual
private:
virtual shared_ptr<Base> copy() const
{
return make_shared<Derived>(*this);
}
};
Base& BaseWrapper::operator += (const Base& other)
{
return *_obj += other;
}
BaseWrapper BaseWrapper::operator +(const Base& other) const
{
return *_obj + other;
}
BaseWrapper Base::operator +(const Base& other) const
{
BaseWrapper result(copy());
result += other;
return result;
}
int main()
{
Derived d1, d2;
Base b, b0;
Base& b1 = d1;
Base& b2 = d2;
b = b1 + b2; // add Derived + Derived, result is Derived (typed Base)
b = b0 + d1; // add Base + Derived, result is Base
// d1 = b0 + d1; // add Base + Derived, result is Base, throws bad_cast (cannot cast to Derived)
d1 = b1 + b2; // add Derived + Derived, result is Derived
return 0;
}
That is, the BaseWrapper can be used to return the polymorphic type by value, and have conversions to the original type. But also note that in this case the memory allocation is involved.
If you want to invoke CharRow::operator+() inside BigIntegerNumber::operator+() you can do it as:
BigIntegerNumber operator+(BigIntegerNumber row2)
{
return CharRow::operator+(row2);
}

Overloading operators "=" and "+" do not work when combined in C++

#include <iostream>
using namespace std;
class A
{
public:
A(int a)
{
length = a;
}
~A(){}
friend A operator +(A& var1, A& var2);
A& operator=(A &other);
int length;
};
A operator +(A& var1, A& var2)
{
return A(var1.length + var2.length);
}
A& A::operator=(A &other)
{
length = other.length;
return *this;
}
int main()
{
A a(1);
A b(2);
A c(3);
c = a; // work
c = a + b; // does not work
cout << c.length ;
return 0;
}
In main(), c = a is successfully compiled but "c = a + b" is not.
However, in A& A::operator=(A &other), if I change (A &other) into (A other) then it works.
Can anyone help me with this case?
The simplest fix is to make your assignment overload take it's parameter by const reference.
Then the temporary returned by a + b can be used with it.
A& A::operator=(A const & other)
{
length = other.length;
return *this;
}
You'll probably want to do the same thing with your operator+ so that c = a + a + a; will work as well.
The problem is that operator + returns a temporary object
friend A operator +(A& var1, A& var2);
But a temporary object may not be bound to a non-const reference that is the type of the parameter of the assignment operator.
A& operator=(A &other);
So the compiler issues an error for statement
c = a + b;
You have three possibility.
The first one os to declare the parameter of the copy assignment operator as constant reference
A& operator=(const A &other);
It is the simplest approach.
The second one is to declare a move assignment operator instead of the copy assignment operator. In this case you explicitly need to define also a copy or move constructor. In this case instead of
c = a;
you have to write
c = std::move( a ); // work
For example
#include <iostream>
using namespace std;
class A
{
public:
A(int a)
{
length = a;
}
~A(){}
friend A operator +(A& var1, A& var2);
A& operator=(A &&other);
A( A && ) = default;
int length;
};
A operator +(A& var1, A& var2)
{
return A(var1.length + var2.length);
}
A& A::operator=(A &&other)
{
length = other.length;
return *this;
}
int main()
{
A a(1);
A b(2);
A c(3);
c = std::move( a ); // work
c = a + b; // does not work
cout << c.length ;
return 0;
}
And at last you could have the both operators simultaneously. For example
#include <iostream>
using namespace std;
class A
{
public:
A(int a)
{
length = a;
}
~A(){}
friend A operator +(A& var1, A& var2);
A& operator=(const A &other);
A& operator=(A &&other);
A( const A & ) = default;
int length;
};
A operator +(A& var1, A& var2)
{
return A(var1.length + var2.length);
}
A& A::operator=(const A &other)
{
length = other.length;
return *this;
}
A& A::operator=(A &&other)
{
length = other.length;
return *this;
}
int main()
{
A a(1);
A b(2);
A c(3);
c = a; // work
c = a + b; // does not work
cout << c.length ;
return 0;
}
In this case in statement
c = a; // work
there will be called the copy assignment operator and in statement
c = a + b; // does not work
there will be called the move assignment operator.
Of course you also may have the copy constructor and move constructor simultaneously the same way as the copy assignment operator and the move assignment operator. For your class you could all them define as defaulted.
For example
#include <iostream>
using namespace std;
class A
{
public:
A(int a)
{
length = a;
}
~A(){}
friend A operator +(A& var1, A& var2);
A& operator=(const A &other) = default;
A& operator=(A &&other) = default;
A( const A & ) = default;
A( A && ) = default;
int length;
};
A operator +(A& var1, A& var2)
{
return A(var1.length + var2.length);
}
int main()
{
A a(1);
A b(2);
A c(3);
c = a; // work
c = a + b; // does not work
cout << c.length ;
return 0;
}

Stucture in C++

I encountered this code but I could not understand the functionality of this code.
It would be a great help if someone could explain it .
struct A{
int i,j;
A(int ii,int jj) : i(ii),j(ii){}
A(const A&a){
}
A& operator =(const A& a){
i=a.i;j=a.j;
}
};
int main()
{
int i;
A a(1,2);
A b(2,3);
A z = (a=b);
cout<<z.i<<" "<<z.j<<endl;
system("pause");
return 0;
}
Explanation:
struct A{
int i,j;//members i and j
A(int ii,int jj) : i(ii),j(ii){} //A constructor. Short form of A(int ii,int jj){i = ii;j = jj;} Original code is wrong too. Should be j(jj) instead of j(ii)
A(const A&a){}//Another constructor. It is missing the assignment
A& operator =(const A& a){
i=a.i;j=a.j;
}//Equal operator overload definition for A = another A. It copies the data from another A and assign to this new one
};
Complete working code:
#include <iostream>
using namespace std;
struct A{
int i,j;
A(int ii,int jj) : i(ii),j(jj){}
A(const A&a){i=a.i;j=a.j;}
A& operator =(const A& a){i=a.i;j=a.j;}
};
int main()
{
int i;
A a(1,2);
A b(2,3);
A z = (a=b);
cout<<z.i<<" "<<z.j<<endl;
return 0;
}
Your problem is this line:
A z = (a=b);
It ends up invoking both your operator= method and your Copy Constructor. When a = b is executed, it uses the operator= method because a already exists and then a reference to a is returned. You're essentially calling a.operator=(b).
When A z = ... is executed, it actually uses the Copy Constructor A(const A&a), not the operator= method because z does not exist yet. Since z is being created by that copy constructor and i and j are never initialized, when you try to print them out, you get whatever junk was located in the memory reserved for i and j.
Another way to view this line:
A z = (a=b);
Is actually like this:
A z(a.operator=(b));
Here's a full example:
int main()
{
A a(1,2);
A b(2,3);
a = b; //calls A& operator=(const A& a)
A z = a; //calls A(const A& a)
}
In conclusion, the fix is to do this:
A(const A& a)
{
i = a.i;
j = a.j;
}
Three mistakes:
1.A(int ii,int jj) : i(ii),j(ii /* jj here? */){}
2.The copy constructor should initialize the members: A(const A&a): i(a.i), j(a.j) {}
3.You should Add return *this in operator=:
A& operator =(const A& a){
i=a.i;j=a.j;
return *this;
}
The OP has asked the operator overloadin part. if we take a as const how can we edit it.
The operator overloading part is:
A& operator =(const A& a){
i=a.i;j=a.j;
}
When you write a=b, you only expect a to change and not b. This is enforced by the const specifier in the function argument definition. This const specifier has nothing to do with whatever appears on the left hand side of the equal sign. It only says that the right hand side of the equal sign will not be modified.