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;
}
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.
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);
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 have class B derived from class A. I call copy constructor that I implemented myself for an object of class B. I also implemented myself a constructor for class A.
Is this copy constructor automatically called when I call copy constructor for class B ? Or how to do this ? Is this the good way:
A::A(A* a)
{
B(a);
// copy stuff
}
thanks!
You can do this with a constructor initialization list, which would look like this:
B::B(const B& b) : A(b)
{
// copy stuff
}
I modified the syntax quite a bit because your code was not showing a copy constructor and it did not agree with your description.
Do not forget that if you implement the copy constructor yourself you should follow the rule of three.
A copy constructor has the signature:
A(const A& other) //preferred
or
A(A& other)
Yours is a conversion constructor. That aside, you need to explicitly call the copy constructor of a base class, otherwise the default one will be called:
B(const B& other) { }
is equivalent to
B(const B& other) : A() { }
i.e. your copy constructor from class A won't be automatically called. You need:
B(const B& other) : A(other) { }
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;
}