In the following :
template<typename Derived>
class Base:
{
inline Derived& operator=(const Base<Derived>& x);
}
Does this declaration erases the default copy assignment operator or do I have two operators :
inline Derived& operator=(const Base<Derived>& x);
// (declared by me)
AND
inline Base<Derived>& operator=(const Base<Derived>& x);
// (declared by the compiler)
In this case, when I call the function, how the compiler will get the right operator ?
If you declare any method that can pass for an assignment operator:
XXX Foo::operator=(Foo&);
XXX Foo::operator=(Foo const&);
XXX Foo::operator=(Foo volatile&);
XXX Foo::operator=(Foo const volatile&);
then the compiler will not generate the default version Foo& operator=(Foo const&);.
Note that the return type is completely free, as for other methods. You could use void, bool, whatever really. It is just idiomatic (but not required) to return a reference to self in order to allow assignment chaining: a = b = c = 0; which itself stems from the guideline that overloaded operators should follow the semantics of their built-in counterparts.
Have you tried? Overloading by return type only would be a compile error, so my guess is that the one defined replaces the default one.
Related
The following code is treated differently by the compilers:
#include <compare>
struct A;
struct I {
virtual std::strong_ordering operator <=>(const A&) const {
return std::strong_ordering::equal;
}
};
struct A : I {
virtual std::strong_ordering operator <=>(const A&) const = default;
};
Both GCC and MSVC accept it, but not Clang which returns the error:
warning: explicitly defaulted three-way comparison operator is implicitly deleted [-Wdefaulted-function-deleted]
virtual std::strong_ordering operator <=>(const A&) const = default;
defaulted 'operator<=>' is implicitly deleted because there is no viable three-way comparison function for base class 'I'
error: deleted function 'operator<=>' cannot override a non-deleted function
virtual std::strong_ordering operator <=>(const A&) const = default;
Demo: https://gcc.godbolt.org/z/WGrGTe89z
It seems that Clang is the only one right here, since I::operator <=>(const I&) const is not defined, so A::operator <=>(const A&) const must be implicitly deleted, and a deleted method cannot override a not deleted method from I. Are the other compilers also within their rights to accept the code?
The other compilers will also reject the code once you write something like A a; a < a;, which makes me think Clang is rejecting it prematurely. In [class.compare.default], the standard says:
A comparison operator function for class C that is defaulted on its first declaration and is not defined as deleted is implicitly defined when it is odr-used or needed for constant evaluation.
Name lookups in the defaulted definition of a comparison operator function are performed from a context equivalent to its function-body.
A definition of a comparison operator as defaulted that appears in a class shall be the first declaration of that function.
Since there is no expression resolving to A::operator<=>(const A&) in your example, no definition is needed and it should not be rejected, even if the function would always end up being deleted.
Lately I often reset an object by assigning a new value to it with operator=. Most of my classes have a copy constructor and operator= defined using "copy and swap" idiom. Which works fine in most cases, albeit not as efficient as it could be, but that mostly does not matter. There is one case that this does not work though. Its when the destructor needs to be called before the constructor of the new object.
Note: most of the classes for which I use this are uncopyable
class Foo
{
public:
Foo() : m_i(0) {}
Foo(int i) : m_i(i) {}
Foo(Foo&& rhs);
Foo& operator=(Foo rhs);
friend void swap(Foo& lhs, Foo& rhs);
private:
Foo(Foo& rhs) {} // uncopyable object
int m_i;
};
Foo::Foo(Foo&& rhs)
: Foo()
{
swap(*this, rhs);
}
Foo& Foo::operator=(Foo rhs)
{
swap(*this, rhs);
return *this;
}
void swap(Foo& lhs, Foo& rhs)
{
using std::swap;
swap(lhs.m_i, rhs.m_i);
}
int main()
{
Foo f(123);
f = Foo(321); // at one time both Foo(123) and Foo(321) exist in memory
}
I have then taught to maybe rewrite operator= to first manually call the destructor and then do the swap (in this case rhs would be taken by const reference). However this answer on stackOverflow made me think otherwise.
I really like operator= to reset my objects, becuase the code is clean and is the same as for built in types (like int). It also uses both the code from constructor and destructor, so no extra code needs to be written and maintained.
So my question is: Is there a way to achieve my goal to reset my object with clean code and no extra code to be written and have the object be destructed before the new one is constructed?
By definition, if you assign a new value to an old object, the new value has been constructed before the assignment can take place.
Your 'old object' is not really destructed, either.
So No. There is no way. And there shouldn't: you shouldn't redefine the 'obvious' behavior of the assignment operator.
But placement new could help here apart from the tilde and exotic construction syntax, maybe this code approaches 'clean' :)
Foo old(a, b, c);
old.~Foo(); // explicit destruction
new (&old) Foo(d, e, f);
If you have code in the constructor that needs to also be called by the assignment operator, then put that code in a private member function and call that from both the destructor and the assignment operator.
You object won't be destructed (and you don't want it to be really), but it will do the same thing as the destructor.
I'm trying to do something I'm not entirely sure is even possible. I'm trying to overload an equals operator something like this:
Class A //Defined somewhere
Struct B{
float bobsAge;
};
B& operator=(A,B){
A.GetAge("bob",B.bobsAge);
return B;
}
Function(getAge){
A Names;
B structNames;
structNames = Names;
}
I understand that this might not be possible, as I understand the operator= is used to do things such as setting one object of the same type equal to another object. Or is this possible to do but I'm doing something wrong.
Thanks ahead of time.
operator= is an assignment operator and can only be overridden inside the class being assigned to. So in your case, it would have to be declared inside A.
"Equals operator," that is, operator==, is used for comparing two objects for equality.
You can overload operator= but it has to be in-class. See http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B for what can be outside of the class definition.
e.g.
class foo {
foo& operator=(B b) {
//...
return *this;
};
};
I'm not exactly sure what you're trying to do with it though.
Also, it's the assignment operator - don't refer to it as the equals operator.
What you are trying to do is to overload the assignment operator However, the standard approach would be to provide a conversion constructor:
class A
{
public:
A(const B& b) { GetAge("bob", b.bobsAge; }
};
And then let that implicit conversion kick in for expressions such as
A a;
B b;
a = b; // Assignment: calls A(const B&), and uses A's default assignment operator
A a2 = b; // Construction: calls A(const B&) and A(const A&)
You could have provided an assignment operator
A& operator=(const B&);
but it seems unintuitive to allow only assignment from B to A, and not construction.
I am very confuse in getting the idea of operator overloading as a member and non member function.
What do we actually mean, when we overload operator as a non-member function and similarly what do we mean when we overload operator as a member functions. Although I know that the non-member functions are the friend functions.
If you overload an operator as a non-member function, you need to specify an object which you want to operate on specifically in your argument list.
If you overload it as a member function, the "this" pointer will do part of the work for you.
Consider the following example:
class Test {
public:
friend Test operator+(const Test &lhs, const Test &rhs); // Non-member function
Test operator+(const Test &rhs); // Member function
};
The difference between the two is that the non-member function doesn't have the this pointer that compiler conveniently passes for you whenever you're talking about a specific instance of a class.
The member function one has the lhs inferred, therefore you need to provide only the rhs.
Please do note that the "friend" is not necessary but if you want to access Test's private members, you need it.
Compiler can disambiguate based on the parameter count. If you wanted to declare friend Test operator+(const Test &rhs), it would complain about insufficiency of arguments because + is a binary operator. The lhs of a member function operator+ is "this".
example
class Foo {
public:
Foo operator+(Foo) // member variant
// declared inside the function
}; // end of class
Foo operator+(Foo lhs, Foo rhs) // non-member variant
{ // declared outside the class
// could be just a call to the member variant
lhs.operator+(rhs);
// I usually do this when implementing std::stream operators,
// don't remember why just now.
}
the non-member does not need to be friended but may be if it need access to internal state.
the non-member has some advantages when it comes to templated code and namespaces on some compilers if I remember correctly, It can also be fine to friend in the non-member variant to document that there is a function outside the class that is somewhat specific to this class. It tells me that if I change that class I may have to look over the non-member operator to make sure that I have not broken anything.
A small example: (I haven't tried compiling this code but I hope it works)
class MyClass
{
public:
MyClass operator+(const MyClass& other) const; //member operator declaration
friend MyClass operator-(const MyClass& first, const MyClass& second); //non-member operator friend declaration
private:
int _a;
}
//member operator definition
MyClass MyClass::operator+(const MyClass& other) const
{
MyClass result;
result._a = _a + other._a;
return result;
}
//non-member operator definition
MyClass MyClass::operator-(const MyClass& first, const MyClass& second)
{
MyClass result;
result._a = first._a - second._a;
return result;
}
Mind the differences: in the member operator definition I don't specify anything before the first _a after "=" - this->_a is assumed.
The member operator functions can be used only if an instance of your class is the first argument of the operator. If, for example you wanted to do something like 2 + myClassObject, you would need to override the non-member operator MyClass MyClass::operator+(int first, const MyClass& second) (or with whatever return value you want this to have).
Note also that I needed the friendship declaration only for my non-member operator to have an access to the private _a field.
Most operators should be defined as members.
class MyClass
{
...
public:
const MyClass& operator+=(const MyClass&);
};
Bit this is identical in behavior to the following:
class MyClass {...};
const MyClass& operator+=(const MyClass&, const MyClass&);
The implied this in the first example is analagous to the first parameter to the second example. If the second example needs access to the internal state of MyClass, it needs to be friended.
class MyClass
{
friend const MyClass& operator+=(const MyClass&, const MyClass&);
};
const MyClass& operator+=(const MyClass&, const MyClass&);
The prototypical exception to this is operator<< on std::ostream.
std::ostream& operator<<(std::ostream&, const MyClass&);
This is logically a member of your MyClass, but because of the ordering of the parameters it would have to be a non-member of both classes or a member of std::ostream. Because you can't add members to std::ostream, this must be defined as a non-member.
class A {
private:
A& operator=(const A&);
};
class B : public A {
public:
B& operator=(const A&) {
return *this;
}
};
int main() {
B b1;
B b2;
b1 = b2;
return 0;
}
This gives error on compilaton:
test.cpp: In member function 'B& B::operator=(const B&)':
test.cpp:16:5: error: 'A& A::operator=(const A&)' is private
test.cpp:19:20: error: within this context
test.cpp: In function 'int main()':
test.cpp:31:7: note: synthesized method 'B& B::operator=(const B&)'
first required here
Build error occurred, build is stopped
Since B::operator=(A&) has a non-standard signature, the compiler generates it's own B::operator=(B&) which (tries) to call A::operator(A&), which is private.
Is there any way I can get the compiler to use B::operator=(A&) also for B arguments?
Sure. Just define the operator yourself and forward the call to operator=(const A&).
class B : public A {
public:
B& operator=(const A&) {
return *this;
}
B& operator=(const B& other) {
return *this = static_cast<const A&>(other);
}
};
This problem is a C++ gotcha that I associate to a bad conception smell.
Your problem is likely a false problem, to which, furthermore, there is no perfect solution. Try as hard as you wish to, there will always be something wrong in the solution implemented.
Here is a (little) more complete answer to this duplicate question: How to use base class's constructors and assignment operator in C++?
BTW, if the assignment operator is private, this is a clear sign that the author of the base class knew very well that entity semantics and value semantics don't mix well. Trust him, he was right!
I think it's a bad idea to try to use operator overloading with inherited types.
In C++ I recommend you to explicitly provide functions for each supported type, when it comes to operator overloading.
I went into this trap myself not too long ago. If you want to look into how experienced c++ people use this feature I recommend you to look into the template specialization of std::vector<bool>.
Maybe above answer may help you to tackle this problem:
C++ Abstract class operator overloading and interface enforcement question
Another possible solution would be:
class B {
public:
B& operator=(const A&) {
return *this;
}
};
class A {
private:
A& operator=(const A&);
public:
operator B() { /* do stuff to convert from A to B */ }
};
int main() {
B b1;
B b2;
b1 = b2;
return 0;
}