saito@sdr.slb.com (Naoki Saito) (12/31/89)
Suppose I have a base class B, and its derived class D. In each class, I defined assignment operator, i.e, X& operator=(X&). Then, B* pb0 = new B(); B* pb1 = new B(); D* pd0 = new D(); D* pd1 = new D(); *pb1 = *pb0 // B& operator=(B&) is invoked. *pd1 = *pd0 // D& operator=(D&) is invoked. This is perfectly fine. However, B* pdb0 = new D(); B* pdb1 = new D(); *pdb1 = *pdb0 // B& operator=(B&) is invoked. I want to use D& operator=(D&) in the above case. Of course, it is possible to do this by explicit casting: *((D*)pdb1) = *((D*)pdb0) // D& operator=(D&) is invoked. Can we invoke D& operator=(D&) without explicit casting? Even if I define B& operator=(B&) as a virtual function, this cannot be done because of the strong type checking, i.e., D& operator=(D&) cannot be binded to virtual B& operator=(B&). Am I asking too much? Regards, -- Naoki Saito (saito@sdr.slb.com) Schlumberger-Doll Research
jimad@microsoft.UUCP (JAMES ADCOCK) (01/04/90)
Try defining the following: virtual B& B::operator=(const B&) virtual B& D::operator=(const B&) [virtual?]D& D::operator=(const D&) Then when using generic pointers to your base class B the second op= will be used to assign to a D pointed to. When using pointers of type D the third op= will be used. In the second op=, if you cannot create a D from a B in general, but only when the B& is really to a D -- then you'll have to resort to runtime checking, and complain at runtime if someone passes you a non-D. Make the third op= virtual if you want to allow the same choices in subclasses of D. If D won't be subclassed, it would be faster to not make the 3rd op= virtual. You'll probably want to define a D::D(B&) too. Alternately, make all your op='s return void, and don't support the infrequent cases where assignment is used for value.
jimad@microsoft.UUCP (JAMES ADCOCK) (01/04/90)
//saito:
//>Suppose I have a base class B, and its derived class D. In each class,
//>I defined assignment operator, i.e, X& operator=(X&). Then,
//consider:
#include <stdio.h>
#include <stdlib.h>
#include "new.h"
class B
{
char* bp;
public:
virtual B& assignTo(B& b) const { b.bp = bp; return b; }
B(char* id="B") { bp = id; }
B(const B& b) { bp = b.bp; }
virtual B& operator=(const B& b) { return b.B::assignTo(*this); }
virtual void Print(char sep='\n') { printf(bp); putchar(sep); }
};
class D : public B
{
char* dp;
protected:
virtual B& assignTo(B& b) const
{ (*(D*)&b).dp = dp; return B::assignTo(b); }
//(except not with MI virtual bases)
public:
D(char* bid="B", char* did="D") : B(bid) { dp = did; }
D(const B& b) : B(b) { dp = "D"; }
D(const D& d) : B(d) { dp = "D"; }
virtual B& operator=(const B& b) { dp = "?"; return b.assignTo(*this); }
virtual D& operator=(const D& d)
{ return *(D*)&(d.D::assignTo(*this)); } //(ditto)
virtual void Print(char sep='\n')
{ B::Print(' '); printf(dp); putchar(sep); }
};
int main()
{
B* pb0 = new B("b0");
B* pb1 = new B("b1");
D* pd0 = new D("db0","d0");
D* pd1 = new D("db1","d1");
*pb1 = *pb0; // B& B::operator=(B&) is invoked.
pb1->Print();
*pd1 = *pd0; // D& D::operator=(D&) is invoked.
pd1->Print();
//This is perfectly fine. However:
B* pdb2 = new D("db2","d2");
B* pdb3 = new D("db3","d3");
*pdb2 = *pdb3; //B& D::operator=(B&) is invoked. No problem.
pdb2->Print();
// But what should we do if someone tries to assign a B to a D ?
B* pdb4 = new D("db4","d4");
B* pb5 = new B("b5");
*pdb4 = *pb5;
pdb4->Print();
return 0;
}