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.
Related
I have te following classes (e.g.) :
class A {
public:
A(void) : i(0) {}
A(int val) : i(val) {}
A(const A& other) : i(other.i) {}
A& operator=(const A& other) {
i = other.i;
return *this;
}
int i;
};
class B : public A {
public:
B(void) : A(), j(0) {};
B(const B& other) : A(other), j(other.j) {}
B(int i, int j) : A(other.i), j(other.j) {}
B& operator=(const B& other) {
A::operator=(other);
j = other.j;
return *this;
}
int j;
};
My question is, given the operator= overload and copy constructor in B, if I wanted to be able to create instances of B out of an already initialized instance of A, or to assign existing instances of A to existing instances of B, would it be necessary to define another copy constructor on B and operator= with the following signature ?:
B(const A& other);
B& operator=(const A& other);
The goal would be to be able to instantiate/assign derived class instances only with the Base class information.
PS : I am working in C++98 and unable to use any newer standard.
Yes, you would have to define something like that.
B(const A& other);
This would allow constructing B out of A. This would also allow assigning A to B by way of implicitly converting A to B and then assigning. So that alone should suffice. But you get an extra copy.
B& operator=(const A& other);
This makes assigning A to B more efficient since you avoid the extra copy of the temporary B. This should also allow assigning things that can be implicitly converted to A like:
B b = 1;
If you don't want that you might have to add some explicit. Did C++98 have explicit? That is so last millenium.
Note: In modern C++ this would be more efficient because of copy elision and because you could use move semantic and perfect forwarding references.
The goal would be to be able to instantiate/assign derived class instances only with the Base class information.
Your goal sounds fishy to me.
Normally in practice, you have two distinct scenarios:
data objects (requiring no inheritance hierarchy)
behavior objects (implementing the same interface, through inheritance).
Data objects (since they have no common base class) implement instantiation and assignment (copy constructors and assignment operators).
Behavior objects (objects within class hierarchies) cannot implement assignment from base class objects in a generic way (what will you do with member variables that exist in the derived class but not in the base class? give them a default value? leave them unchanged?).
That said, you should use a different API than copy constructor and assignment in order to avoid confusion and implicit casts.
That is, if you have both:
B& operator=(const B&);
B& operator=(const A&);
then this is ambiguous when the code assigns from a B instance (as the compiler could call either of them).
You could add a B::copy_common_values(const A&);. This would make it more explicit as well.
In case you are trying to solve an x-y problem, also look up prototype design pattern.
I have a class B deriving from A. A implements copy constructor and assignment operator. I have copy constructor for B and want to implement assignment for B. My approach (most likely incorrect) is
B& B::operator=(const B& other) {
B tmp (other);
std::swap <A>(*this, tmp);
std::swap (m_member, other.m_member);
}
Can something like this work? I have looked on the web for specializations of std::swap to a basis class but have not found something usefull.
You can check this stackoverflow thread (calling operators of base class... safe?) on how to use operator = from base class.
What I don't understand is why you are using swap. You should instead do something like this:
B& B::operator=(const B& other) {
A::operator = (other);
this->m_member = other.m_member;
return *this;
}
In GCC 4.6, it is possible to inherit a parent's assignment operators even when the child's assignment operators are implicitly deleted due to a move constructor. In later versions of GCC (as well as Clang), this is no longer possible. What is the proper way to have the child class use the parent's assignment operators?
struct A
{
A & operator=(A const & other) = default;
};
struct B : public A
{
B() {}
B(B && other) {}
using A::operator=;
};
int main()
{
B b1, b2;
b1 = b2; // error: use of deleted function because B's operator= is implicitly deleted due to move constructor
return 0;
}
A function that is deleted is still declared, only the definition is deleted. Expanding that in your class definition:
struct B : A {
using A::operator=; // A& operator=(const A&)
B& operator=(const B&) = delete;
};
At this point, you can note that there are two declarations for operator= in the derived type, the first one (brought into scope by means of a using-declaration) takes a const A& argument, while the second one takes a const B& and is deleted.
When you later try the assignment:
B b1, b2;
b1 = b2;
Both declarations are seen by the compiler and the second one is a better match. Because it is marked as deleted you get the error. If you had, on the other hand assigned a A object it would have worked as expected:
B b1, b2;
b1 = static_cast<A&>(b2); // works, BUT...
The problem with this approach is that it is only copying the base subobjects which is probably not what you want. If you just want the same behavior you would have had if the assignment had been generated by the compiler you need to ask for it:
struct B : A {
// ...
B& operator=(const B&) = default;
};
It would depend on what you want to have happen when you assign a derived type to itself. If you want the child assignment operator to work like "normal" despite the move operator suppressing the implicit generation, you can simply bring the child assignment back into the class, using this:
B &operator=( B const & ) = default;
This would likely be equivalent to what GCC 4.6 did. I believe GCC 4.6 doesn't properly suppress generated operators as the standard requires, so you were probably just getting the normal assignment operator behavior, along with any overloads from the base class that your using declaration was pulling in.
If you actually only want to assign the base part of the class, you would need to implement your own assignment operator:
B &operator=( B const &that ) {
static_cast<A&>(*this) = that;
return *this;
}
Unfortunately I don't have GCC 4.7 to try out right now, but I wouldn't be surprised if you are actually getting the base class assignment operator in your derived class, but the derived class's deleted assignment operator is a better match for your example. You could test this out by trying this line in your main():
b1 = static_cast<A const&>(b2);
Is this a valid way to create an assignment operator with members that are references?
#include <new>
struct A
{
int &ref;
A(int &Ref) : ref(Ref) { }
A(const A &second) : ref(second.ref) { }
A &operator =(const A &second)
{
if(this == &second)
return *this;
this->~A();
new(this) A(second);
return *this;
}
}
It seems to compile and run fine, but with c++ tendency to surface undefined behavior when least expected, and all the people that say its impossible, I think there is some gotcha I missed. Did I miss anything?
It's syntactically correct. If the placement new throws, however, you
end up with an object you can't destruct. Not to mention the disaster
if someone derives from your class. Just don't do it.
The solution is simple: if the class needs to support assignment, don't
use any reference members. I have a lot of classes which take reference
arguments, but store them as pointers, just so the class can support
assignment. Something like:
struct A
{
int* myRef;
A( int& ref ) : myRef( &ref ) {}
// ...
};
Another solution is to use the reference_wrapper class ( in functional header ) :
struct A
{
A(int& a) : a_(a) {}
A(const A& a) : a_(a.a_) {}
A& operator=(const A& a)
{
a_ = a.a_;
return *this;
}
void inc() const
{
++a_;
}
std::reference_wrapper<int>a_;
};
What you do its technically correct as far as I know, but it generates trouble. For instance, consider what happens with a derived class from A, since its assignment operator generates a new object (slicing). Can't you just turn the reference into a pointer within your class?
Besides that, copy constructors and assignment operators usually take its argument by const&.
What you do is correct, but it is not very exception safe way of writing an copy assignment operator. Also, You should consider using a pointer member rather than an reference member.
You should implement it using the Copy and Swap Idiom. It has atleast 3 advantages over your implementation.
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;
}