I have a question about operator= that accepts parent reference type.
When there is a abstract class and it's implemented class,
why is not enough to have single operator= that accept parent reference type?
Below is my code
#include <iostream>
class AbstractType {
public:
virtual ~AbstractType() {}
virtual AbstractType& operator=(const AbstractType& other) {
std::cout << "AbstractType& operator=(const AbstractType&)" << std::endl;
return *this;
}
};
class Type1: public AbstractType {
public:
virtual ~Type1() {}
virtual Type1& operator=(const AbstractType& other) {
std::cout << "Type1& operator=(const AbstractType&)" <<
std::endl;
return *this;
}
/*
virtual Type1& operator=(const Type1& other) {
std::cout << "Type1& operator=(const Type1&)" << std::endl;
// Just redirecting here! What a waste!
return operator=(dynamic_cast<const AbstractType&>(other));
}
*/
};
int main()
{
Type1 t1;
AbstractType& r1 = t1;
Type1 t2;
AbstractType& r2 = t2;
// Type1& operator=(const AbstractType&). It's fine!
r1 = r2;
// AbstractType& operator=(const AbstractType&)!! Why??
// Expected `Type1& operator=(const AbstractType&)` to be called!
t1 = t2;
return 0;
}
You can find given parameter is being just redirected in Type1& operator=(const Type1&) that is ignored by comment.
Uncomment Type1& operator=(const Type1&) is just working for me,
but if say, I have more than a hundred of TypeX then I have to make two hundred of copy assignment which is I can't understand because it seems to me just having Type1& operator=(const AbstractType& other) is enough.
And most cases I only have AbstractType to handle things around.
Very rare to know it's specific type in advance under limited situations.
Anyone can suggest me better solution?
// AbstractType& operator=(const AbstractType&)!! Why??
// Expected `Type1& operator=(const AbstractType&)` to be called!
t1 = t2;
Here you are calling:
t1.operator=(t2);
Since t1 and t2 have Type1, the compiler will match the following function:
Type1 & Type1::operator=(const Type1 &);
which is the implicitly-defined copy assignment operator, and which will call the copy assignment operator of the base:
AbstractType & AbstractType::operator=(const AbstractType &);
However, this call is not dynamically dispatched -- which is the reason you end up seeing your results.
Uncomment Type1& operator=(const Type1&) is just working for me
Note that:
There is no need for dynamic_cast.
There is no need to make a virtual call.
The operator itself does not need to be virtual.
In other words, you can simplify to:
Type1& operator=(const Type1& other)
{
return Type1::operator=(static_cast<const AbstractType&>(other));
}
Because of Liskovs substitution principle, which states that if a program, module or function is using a Base class, then the reference of Base class can be replaced with Derived class without affecting programs functionality. So in your particular case, implementing it in terms of Curiously recurring template pattern will be an elegant solution. Please see link for more info!
Related
template<typename T = uint8_t> class ArrayRef {
using uint = unsigned int;
protected:
ArrayRef() {}
ArrayRef(const ArrayRef&) {}
ArrayRef& operator=(const ArrayRef& other) { return *this; }
};
class ByteArray : ArrayRef<uint8_t> {
ByteArray(const ArrayRef&);
ByteArray& operator=(const ArrayRef&);
public:
ByteArray() {}
};
class Base {
using uint = unsigned int;
protected:
Base() {}
Base(const Base&) {}
Base& operator=(const Base& other) { return *this; }
};
class Derived : Base {
Derived(const Derived&);
Derived& operator=(const Derived& other) { return *this; }
public:
Derived() {}
};
int main() {
ByteArray ba;
ByteArray ba2 = ba; // no error, why?
ba = ba2; // no error why?
Derived d;
Derived d2 = d; // error (expected) - Calling a private constructor
d = d2; // error (expected) - Calling private assignment operator
}
Two questions about the code above.
Can you explain why the templated code behaves differently than the non-templated code? (see the comments in main().
How would I go about creating private copy constructors and assignment operators properly for templated code like this, in order to prevent object copies?
Can you explain why the templated code behaves differently than the non-templated code? (see the comments in main().
The difference does not have anything to do with templates.
The difference is that your copy constructor and copy assignment operator are implicitly defined (as public) in ByteArray. In Derived you've made them private. If you take the template out of the question, it may be easier to see the difference between your two versions:
class ArrayRef {
protected:
ArrayRef() {}
ArrayRef(const ArrayRef&) {}
ArrayRef& operator=(const ArrayRef& other) { return *this; }
};
class ByteArray : ArrayRef {
ByteArray(const ArrayRef&); // your converting ctor
ByteArray& operator=(const ArrayRef&); // your converting assignment op
public:
ByteArray() {}
// copy contructor - implicitly defined:
// ByteArray(const ByteArray&) = default;
// copy assignment operator - implicitly defined:
// ByteArray& operator=(const ByteArray&) = default;
};
If you now try copying a ByteArray it will work just as fine as when it was based on an instance of a class template. Compare the above ByteArray with your Derived in which you've actually made the copy constructor and copy assignment operator private.
How would I go about creating private copy constructors and assignment operators properly for templated code like this, in order to prevent object copies?
In order to prevent copies, you may delete them:
class ByteArray : private ArrayRef<uint8_t> {
public:
ByteArray(const ByteArray&) = delete;
ByteArray& operator=(const ByteArray&) = delete;
ByteArray() {}
};
or make them private to allow ByteArrays and friends to make copies:
class ByteArray : private ArrayRef<uint8_t> {
private:
ByteArray(const ByteArray&) { ... }; // or `= default`
ByteArray& operator=(const ByteArray&) { ...; return *this; } // or `= default`
public:
ByteArray() {}
};
Note that the private (converting) constructor and (converting) assignment operator that takes a const ArrayRef<uint8_t>& as input does not prevent the implicitly defined copy constructor and copy assignment operator that takes a const ByteArray& as input from behing created in ByteArray.
In your Derived class, you've actually made the copy constructor and copy assignment operator private which is why you get the expected compilation errors when trying to use those.
Here's a full example that includes your (converting) constructor and assignment operator as well as a (user defined) copy constructor and copy assignment operator.
#include <cstdint>
#include <iostream>
template<typename T = uint8_t> class ArrayRef {
protected:
ArrayRef() {}
ArrayRef(const ArrayRef&) {}
ArrayRef& operator=(const ArrayRef& other) { return *this; }
};
class ByteArray : ArrayRef<uint8_t> {
ByteArray(const ArrayRef&) { std::cout << "your converting ctor\n"; }
ByteArray& operator=(const ArrayRef&) {
std::cout << "your converting assignment op\n"; return *this;
}
public:
ByteArray(const ByteArray&) { std::cout << "copy ctor\n"; }
ByteArray& operator=(const ByteArray&) {
std::cout << "copy assignment op\n"; return *this;
}
ByteArray() {}
};
int main() {
ByteArray a;
ByteArray b = a;
a = b;
}
You can see in the output that none of your private methods are used:
copy ctor
copy assignment op
Consider the assignment operators in classes Parent and Child, below.
#include <iostream>
class Parent
{
public:
Parent(){};
virtual ~Parent(){};
Parent& operator=(const Parent& other){mP = other.mP; return *this;};
void setP(double inP){mP = inP;};
double getP(){return mP;};
protected:
double mP;
};
class Child : public virtual Parent
{
public:
Child(){};
virtual ~Child(){};
Child& operator=(const Child& other)
{
mC = other.mC;
mP = other.mP;// this line
return *this;
};
void setC(double inC){mC = inC;};
double getC(){return mC;};
protected:
double mC;
};
Is here a way to avoid the duplicate line mP = other.mP;?
The reason I am asking is that as the number of bases get higher and the inheritance structure gets more complicated, it is easy to lose track of members.
EDIT
The reason I need to implement the operator= is that it needs to check some things before the assignments.
Just call the Parent operator:
Child& operator=(const Child& other)
{
mC = other.mC;
Parent::operator=(other);
return *this;
}
Or really, don't implement either operator since both are trivial!
The best way to avoid this issue is to remove both of your operator= functions.
The compiler-generated operator= applies operator= to each member variable and base class, which is just what you were trying to do anyway.
Re-implementing the wheel just makes your code harder to read and maintain -- and sometimes less efficient.
Child& operator=(const Child& other) {
mC = other.mC;
mP = other.mP;
}
you can invoke the assignment operator of the parent prior to the child specific assignment in this way:
Child& operator=(const Child& other)
{
Parent::operator=(other);
mC = other.mC;
return *this;
};
How can I make a Class non-cloneable like we can do in Java while creating singleton.
Is there any condition we can put on copy constructor so that an exception can be thrown if user tries to make a copy of an object?
I am a novice in C++ so kindly add any info to this or redirect if an answer is already available for the same.
Just declare copy constructor and copy assign operator private
in C++03
class NonCopyable
{
public:
NonCopyable() { }
private:
NonCopyable(const NonCopyable&);
NonCopyable& operator=(const NonCopyable&);
};
Also you can make a class derive from NonCopyable, AnotherType is un-copyable
class AnotherNonCopyable : private NonCopyable
{
public:
AnotherNonCopyable () {}
}
With C++11:
class NonCopyableType
{
public:
NonCopyableType(const NonCopyableType&) = delete;
NonCopyableType& operator=(const NonCopyableType&) = delete;
};
You can delete the copy constructor and assignment operator:
struct Foo
{
Foo(const& Foo) = delete;
Foo& operator=(const Foo&) = delete;
};
If you don't have C++11 support, make them private, and don't implement them:
struct Foo
{
private:
Foo(const& Foo);
Foo& operator=(const Foo&);
};
Note In C++, class and struct are essentially the same.
Declare the copy-semantics as delete:
//C++11 only
MyClass(MyClass const &) = delete;
MyClass& operator=(MyClass const &) = delete;
That makes the class non-copyable!
//pre-C++11 code
private:
MyClass(MyClass const &); //declare only, don't define it
MyClass& operator=(MyClass const &); //declare only, don't define it
This should also work!
Is there any condition we can put on copy constructor so that an
exception can be thrown if user tries to make a copy of an object.
if you make the copy constructor private, The code will not compile when the programmer tries to make another copy. This is probably better than detecting the error with an exception at runtime.
class foo {
private:
operator = ( const foo& f);
};
Trying to resolve error C2248 related to abstract base class using implementation of copy/move ctors/assignment operators and dtor (Rule of Five) and a few questions come up:
1) Why does the rule of 5, primarily relating to the dtor, apply when the unique_ptr data members are handled automatically? The dtor implementation should be left empty correct, since the unique_ptrs are automatically destroyed once their owners go out of scope?
2) Suppose another class had a member of type std::unique_ptr of a vector of the same type. In order for this class to be copyable, it must have a copy ctor and copy assignment operator that clone the unique_ptr data member? I have seen this solution, but is seems like the original poster just switched over to shared_ptr for the sake of removing the error alone with little consideration of ownership management. Is this the correct strategy?
3) Consider the same case as question 2 above relating to vector of unique_ptr. Should dtor include a call to clear() the vector?
4) The assignment operators for the Derived1 are not correct. But the base class is supposed to have copy and move assignment operators, since it has copy/move ctors (rule of 4/5). These can't actually be used outside of the class since it is abstract and thus no instances will be assigned. But how do I utilize this code from the derived classes? Each derived class needs to be able to move/copy the base data members and it's own data members. I'm not sure what to do.
#include <algorithm>
#include <memory>
#include <vector>
#include <iostream>
class Base{
public:
Base() : m_subBases(){};
/* copy ctor */
Base(const Base& other) : m_subBases(){
*this = other;
};
/* move ctor */
Base(Base&& other) : m_subBases(){
*this =std::move( other);
};
/* Move assignment operator*/
Base& operator=(Base&& other){
m_subBases = std::move(other.m_subBases);
return *this;
};
/* Copy assignment operator */
Base& operator=(const Base& other){
for(int i = 0; i < other.m_subBases.size(); i++)
m_subBases.push_back(other.m_subBases[i]->clone());
return *this;
};
/* virtual dtor */
virtual ~Base(){
m_subBases.clear();
};
/* Used for creating clones of unique_ptrs */
virtual std::unique_ptr <Base> clone() const= 0;
/* Do something */
virtual void execute(float f) = 0;
//Omitted data member access methods
protected:
std::vector < std::unique_ptr <Base> > m_subBases;
};
class Derived1 : public Base{
public:
Derived1() : Base(){};
/* copy ctor */
Derived1(const Derived1& other) : Base(other){
*this = other;
};
/* move ctor */
Derived1(Derived1&& other) : Base(std::move(other)){
*this = std::move(other);
};
/* Move assignment operator*/
Derived1& operator=(Derived1&& other){
//This is redundant when called in the move ctor because
// of the call to Base(std::move(other))
m_subBases = std::move(other.m_subBases);
m_string = other.m_string;
return *this;
};
/* Copy assignment operator */
Derived1& operator=( const Derived1& other){
//This is redundant when called in the copy ctor because
// of the call to Base(other)
for(int i = 0; i < other.m_subBases.size(); i++)
m_subBases.push_back(other.m_subBases[i]->clone());
m_string = other.m_string;
return *this;
};
/* virtual dtor */
virtual ~Derived1(){};
/* Used for creating clones of unique_ptrs */
virtual std::unique_ptr <Base> clone() const{
return std::unique_ptr <Base> (new Derived1(*this));
};
virtual void execute(float f){
std::cout << "Derived1 " << f << std::endl;
};
protected:
std::string m_string;
};
I'd like to offer an alternative approach. Not the Scary Rule of Five, but the Pleasant Rule of Zero, as #Tony The Lion has already suggested. A full implementation of my proposal has been coded by several people, and there's a fine version in #R. Martinho Fernandes's library, but I'll present a simplified version.
First, let's recap:
The Rule of Zero: Don't write a copy- or move-constructor, a copy- or move-assignment operator, or a destructor. Instead, compose your class of components which handle a single responsibility and encapsulate the desired behaviour for the individual resource in question.
There's an obvious caveat: When you design the single-responsibility class, you must of course obey:
The Rule of Five: If you write any one of copy- or move-constructor, copy- or move-assignment operator, or destructor, you must implement all five. (But the "five" functions needed by this rule are actually: Destructor, Copy-Const, Move-Const, Assignment and Swap.)
Let's do it. First, your consumer:
struct X;
struct Base
{
std::vector<value_ptr<X>> v;
};
struct Derived : Base
{
};
Note that both Base and Derived obey the Rule of Zero!
All we need to do is implement value_ptr. If the pointee is non-polymorphic, the following will do:
template <typename T>
class value_ptr
{
T * ptr;
public:
// Constructors
constexpr value_ptr() noexcept : ptr(nullptr) { }
constexpr value_ptr(T * p) noexcept : ptr(p) { }
// Rule of Five begins here:
~value_ptr() { ::delete ptr; }
value_ptr(value_ptr const & rhs) : ptr(rhs.ptr ? ::new T(*rhs.ptr) : nullptr) { }
value_ptr(value_ptr && rhs) noexcept : ptr(rhs.ptr) { rhs.ptr = nullptr; }
value_ptr & operator=(value_ptr rhs) { swap(rhs); return *this; }
void swap(value_ptr & rhs) noexcept { std::swap(rhs.ptr, ptr); }
// Pointer stuff
T & operator*() const noexcept { return *ptr; }
T * operator->() const noexcept { return ptr; }
};
template <typename T, typename ...Args>
value_ptr<T> make_value(Args &&... args)
{
return value_ptr<T>(::new T(std::forward<Args>(args)...));
}
If you would like smart pointer that handles polymorphic base class pointers, I suggest you demand that your base class provide a virtual clone() function, and that you implement a clone_ptr<T>, whose copy constructor would be like this:
clone_ptr(clone_ptr const & rhs) : ptr(rhs.ptr ? rhs.ptr->clone() : nullptr) { }
Assignment Operator in C++ can be made virtual. Why is it required? Can we make other operators virtual too?
The assignment operator is not required to be made virtual.
The discussion below is about operator=, but it also applies to any operator overloading that takes in the type in question, and any function that takes in the type in question.
The below discussion shows that the virtual keyword does not know about a parameter's inheritance in regards to finding a matching function signature. In the final example it shows how to properly handle assignment when dealing with inherited types.
Virtual functions don't know about parameter's inheritance:
A function's signature needs to be the same for virtual to come into play. So even though in the following example, operator= is made virtual, the call will never act as a virtual function in D, because the parameters and return value of operator= are different.
The function B::operator=(const B& right) and D::operator=(const D& right) are 100% completely different and seen as 2 distinct functions.
class B
{
public:
virtual B& operator=(const B& right)
{
x = right.x;
return *this;
}
int x;
};
class D : public B
{
public:
virtual D& operator=(const D& right)
{
x = right.x;
y = right.y;
return *this;
}
int y;
};
Default values and having 2 overloaded operators:
You can though define a virtual function to allow you to set default values for D when it is assigned to variable of type B. This is even if your B variable is really a D stored into a reference of a B. You will not get the D::operator=(const D& right) function.
In the below case, an assignment from 2 D objects stored inside 2 B references... the D::operator=(const B& right) override is used.
//Use same B as above
class D : public B
{
public:
virtual D& operator=(const D& right)
{
x = right.x;
y = right.y;
return *this;
}
virtual B& operator=(const B& right)
{
x = right.x;
y = 13;//Default value
return *this;
}
int y;
};
int main(int argc, char **argv)
{
D d1;
B &b1 = d1;
d1.x = 99;
d1.y = 100;
printf("d1.x d1.y %i %i\n", d1.x, d1.y);
D d2;
B &b2 = d2;
b2 = b1;
printf("d2.x d2.y %i %i\n", d2.x, d2.y);
return 0;
}
Prints:
d1.x d1.y 99 100
d2.x d2.y 99 13
Which shows that D::operator=(const D& right) is never used.
Without the virtual keyword on B::operator=(const B& right) you would have the same results as above but the value of y would not be initialized. I.e. it would use the B::operator=(const B& right)
One last step to tie it all together, RTTI:
You can use RTTI to properly handle virtual functions that take in your type. Here is the last piece of the puzzle to figure out how to properly handle assignment when dealing with possibly inherited types.
virtual B& operator=(const B& right)
{
const D *pD = dynamic_cast<const D*>(&right);
if(pD)
{
x = pD->x;
y = pD->y;
}
else
{
x = right.x;
y = 13;//default value
}
return *this;
}
It depends on the operator.
The point of making an assignment operator virtual is to allow you from the benefit of being able to override it to copy more fields.
So if you have an Base& and you actually have a Derived& as a dynamic type, and the Derived has more fields, the correct things are copied.
However, there is then a risk that your LHS is a Derived, and the RHS is a Base, so when the virtual operator runs in Derived your parameter is not a Derived and you have no way of getting fields out of it.
Here is a good discussio:
http://icu-project.org/docs/papers/cpp_report/the_assignment_operator_revisited.html
Brian R. Bondy wrote:
One last step to tie it all together, RTTI:
You can use RTTI to properly handle virtual functions that take in your type. Here is the last piece of the puzzle to figure out how to properly handle assignment when dealing with possibly inherited types.
virtual B& operator=(const B& right)
{
const D *pD = dynamic_cast<const D*>(&right);
if(pD)
{
x = pD->x;
y = pD->y;
}
else
{
x = right.x;
y = 13;//default value
}
return *this;
}
I would like to add to this solution a few remarks. Having the assignment operator declared the same as above has three issues.
The compiler generates an assignment operator that takes a const D& argument which is not virtual and does not do what you may think it does.
Second issue is the return type, you are returning a base reference to a derived instance. Probably not much of an issue as the code works anyway. Still it is better to return references accordingly.
Third issue, derived type assignment operator does not call base class assignment operator (what if there are private fields that you would like to copy?), declaring the assignment operator as virtual will not make the compiler generate one for you. This is rather a side effect of not having at least two overloads of the assignment operator to get the wanted result.
Considering the base class (same as the one from the post I quoted):
class B
{
public:
virtual B& operator=(const B& right)
{
x = right.x;
return *this;
}
int x;
};
The following code completes the RTTI solution that I quoted:
class D : public B{
public:
// The virtual keyword is optional here because this
// method has already been declared virtual in B class
/* virtual */ const D& operator =(const B& b){
// Copy fields for base class
B::operator =(b);
try{
const D& d = dynamic_cast<const D&>(b);
// Copy D fields
y = d.y;
}
catch (std::bad_cast){
// Set default values or do nothing
}
return *this;
}
// Overload the assignment operator
// It is required to have the virtual keyword because
// you are defining a new method. Even if other methods
// with the same name are declared virtual it doesn't
// make this one virtual.
virtual const D& operator =(const D& d){
// Copy fields from B
B::operator =(d);
// Copy D fields
y = d.y;
return *this;
}
int y;
};
This may seem a complete solution, it's not. This is not a complete solution because when you derive from D you will need 1 operator = that takes const B&, 1 operator = that takes const D& and one operator that takes const D2&. The conclusion is obvious, the number of operator =() overloads is equivalent with the number of super classes + 1.
Considering that D2 inherits D, let's take a look at how the two inherited operator =() methods look like.
class D2 : public D{
/* virtual */ const D2& operator =(const B& b){
D::operator =(b); // Maybe it's a D instance referenced by a B reference.
try{
const D2& d2 = dynamic_cast<const D2&>(b);
// Copy D2 stuff
}
catch (std::bad_cast){
// Set defaults or do nothing
}
return *this;
}
/* virtual */ const D2& operator =(const D& d){
D::operator =(d);
try{
const D2& d2 = dynamic_cast<const D2&>(d);
// Copy D2 stuff
}
catch (std::bad_cast){
// Set defaults or do nothing
}
return *this;
}
};
It is obvious that the operator =(const D2&) just copies fields, imagine as if it was there. We can notice a pattern in the inherited operator =() overloads. Sadly we cannot define virtual template methods that will take care of this pattern, we need to copy and paste multiple times the same code in order to get a full polymorphic assignment operator, the only solution I see. Also applies to other binary operators.
Edit
As mentioned in the comments, the least that can be done to make life easier is to define the top-most superclass assignment operator =(), and call it from all other superclass operator =() methods. Also when copying fields a _copy method can be defined.
class B{
public:
// _copy() not required for base class
virtual const B& operator =(const B& b){
x = b.x;
return *this;
}
int x;
};
// Copy method usage
class D1 : public B{
private:
void _copy(const D1& d1){
y = d1.y;
}
public:
/* virtual */ const D1& operator =(const B& b){
B::operator =(b);
try{
_copy(dynamic_cast<const D1&>(b));
}
catch (std::bad_cast){
// Set defaults or do nothing.
}
return *this;
}
virtual const D1& operator =(const D1& d1){
B::operator =(d1);
_copy(d1);
return *this;
}
int y;
};
class D2 : public D1{
private:
void _copy(const D2& d2){
z = d2.z;
}
public:
// Top-most superclass operator = definition
/* virtual */ const D2& operator =(const B& b){
D1::operator =(b);
try{
_copy(dynamic_cast<const D2&>(b));
}
catch (std::bad_cast){
// Set defaults or do nothing
}
return *this;
}
// Same body for other superclass arguments
/* virtual */ const D2& operator =(const D1& d1){
// Conversion to superclass reference
// should not throw exception.
// Call base operator() overload.
return D2::operator =(dynamic_cast<const B&>(d1));
}
// The current class operator =()
virtual const D2& operator =(const D2& d2){
D1::operator =(d2);
_copy(d2);
return *this;
}
int z;
};
There is no need for a set defaults method because it would receive only one call (in the base operator =() overload). Changes when copying fields are done in one place and all operator =() overloads are affected and carry their intended purpose.
Thanks sehe for the suggestion.
virtual assignment is used in below scenarios:
//code snippet
Class Base;
Class Child :public Base;
Child obj1 , obj2;
Base *ptr1 , *ptr2;
ptr1= &obj1;
ptr2= &obj2 ;
//Virtual Function prototypes:
Base& operator=(const Base& obj);
Child& operator=(const Child& obj);
case 1: obj1 = obj2;
In this virtual concept doesn't play any role as we call operator= on Child class.
case 2&3: *ptr1 = obj2;
*ptr1 = *ptr2;
Here assignment won't be as expected. Reason being operator= is called on Base class instead.
It can be rectified using either:
1) Casting
dynamic_cast<Child&>(*ptr1) = obj2; // *(dynamic_cast<Child*>(ptr1))=obj2;`
dynamic_cast<Child&>(*ptr1) = dynamic_cast<Child&>(*ptr2)`
2) Virtual concept
Now by simply using virtual Base& operator=(const Base& obj) won't help as signatures are different in Child and Base for operator=.
We need to add Base& operator=(const Base& obj) in Child class along with its usual Child& operator=(const Child& obj) definition. Its important to include later definition, as in the absence of that default assignment operator will be called.(obj1=obj2 might not give desired result)
Base& operator=(const Base& obj)
{
return operator=(dynamic_cast<Child&>(const_cast<Base&>(obj)));
}
case 4: obj1 = *ptr2;
In this case compiler looks for operator=(Base& obj) definition in Child as operator= is called on Child. But since its not present and Base type can't be promoted to child implicitly, it will through error.(casting is required like obj1=dynamic_cast<Child&>(*ptr1);)
If we implement according to case2&3, this scenario will be taken care of.
As it can be seen virtual assignment makes call more elegant in case of assignments using Base class pointers/reference .
Can we make other operators virtual too? Yes
It's required only when you want to guarantee that classes derived from your class get all of their members copied correctly. If you aren't doing anything with polymorphism, then you don't really need to worry about this.
I don't know of anything that would prevent you from virtualizing any operator that you want--they're nothing but special case method calls.
This page provides an excellent and detailed description of how all this works.