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; }