1

[over.ass]/2

I can understand why bptr->operator=(dobj2); calls D& operator= (const B&) and why dobj1 = dobj2; calls the implicitly-declared D::operator=(const D&). But I'm not so sure about *bptr = dobj2;.

Example:

struct B {
    virtual int operator= (int);
    virtual B& operator= (const B&);
};
struct D : B {
    virtual int operator= (int);
    virtual D& operator= (const B&);
};

D dobj1;
D dobj2;
B* bptr = &dobj1;
void f() {
    bptr->operator=(99); // calls D::operator=(int)
    *bptr = 99; // ditto
    bptr->operator=(dobj2); // calls D::operator=(const B&)
    *bptr = dobj2; // ditto
    dobj1 = dobj2; // calls implicitly-declared D::operator=(const D&)
}
Ayrosa
  • 3,385
  • 1
  • 18
  • 29
  • Virtual assignment operators are *extremely* unusual. Think Unicorns. – Bo Persson Apr 16 '18 at 21:42
  • But they are virtual functions just like any other virtual function. – Ayrosa Apr 16 '18 at 21:43
  • 1
    Yes, but you are never going to need one in real code. Especially if we cannot tell what it does, and how it interferes with the compiler generated default assignment operators. – Bo Persson Apr 16 '18 at 21:46
  • 1
    Perhaps you should make clear that a) the code is abstracted from the standard, and b) what you expect the code to do, and why you don't understand what it does. –  Apr 16 '18 at 21:54
  • 1
    `*bptr = dobj2;` is just another, more compact way to write `bptr->operator=(dobj2);` I don't quite grasp the nature of your confusion. – Igor Tandetnik Apr 16 '18 at 21:56
  • If you could show me this, using a standard quote I would appreciate. – Ayrosa Apr 16 '18 at 21:58
  • 1
    **[over.match.oper]/2** and in particular Table 12 "Relationship between operator and function call notation" – Igor Tandetnik Apr 16 '18 at 22:05

2 Answers2

2

Polymorphism happens when you have a Base pointer or reference to a derived instance and calls a virtual member function on it.

In your examples

bptr->operator=(99); // calls D::operator=(int)
bptr->operator=(dobj2); // calls D::operator=(const B&)

A base pointer points to a derived instance is calling the virtual functions => Invoke polymorphism => the derived versions will be called.

*bptr = 99; // ditto
*bptr = dobj2; // ditto

This is simply

(*bptr).operator=(99);
(*bptr).operator=(dobj2);

Or a base reference to a derived instance is calling the virtual functions => Invoke polymorphism => the derived versions will be called.

dobj1 = dobj2; // calls implicitly-declared D::operator=(const D&)

No more polymorphism since the caller(dobj1) is not a (base) reference/pointer. Invoked the D::operator=(const D&) generated by the compiler, which also calls the operator = of the base class automatically.

virtual B& operator= (const B&);
gchen
  • 1,173
  • 1
  • 7
  • 12
  • But how do you show that `*bptr` is a D object and not a B object? I know that's very basic, but I'm exhausted to try to find this in the spec by myself. Could you help me with that? – Ayrosa Apr 16 '18 at 23:11
  • See this explanation https://stackoverflow.com/a/3082442/9281750. You can treat *bptr as a B& to an D object. Thus, it invokes the polymorphism. – gchen Apr 17 '18 at 00:20
  • I would like to find in the Standard something similar to what sbi said in his answer: `*ptr doesn't result in an object, but in a reference Base& to the object`., so far to no avail. – Ayrosa Apr 17 '18 at 00:57
  • In other words, I'd like to know where in the Standard does it say that the dynamic type of the `*bptr` object is D, not B? As I said before I'm very tired. I must get some sleep. – Ayrosa Apr 17 '18 at 01:02
  • *bptr gets what is pointed to by bptr, and what sits there is a D. The static type should be a B(&), but why would its dynamic type be a B when the object is a D...As others have mentioned, it's just the same/another way of writing bptr->operator=(dobj2); Sorry if this is still confusing, and I also do not find any helpful documentations. – gchen Apr 17 '18 at 01:48
  • 1
    I think I have found the answer in the Standard: [expr.unary.op]/1(http://eel.is/c++draft/expr.unary.op#1) – Ayrosa Apr 17 '18 at 07:54
  • @Ayrosa "_in a reference Base&_" This would be incorrect: in C++ **expressions never have reference type**. Expression can have types mentioning a reference somewhere, like "pointer to function type returning a reference to int", just not reference type. The expression `*bptr` just has type `B`. – curiousguy Apr 26 '18 at 23:49
  • @gchen "_The static type should be a B(&),_" The concept of reference just doesn't work that way in the C++ type system, or in C type system (which doesn't have references, but which is similar just more restricted); there is in fact a common C/C++ basic principle of the type system which is grounded on expressions have both a type and a lvalue-ness or rvalue vs. lvalue (or something). When something is usually a rvalue but something is declared with a reference type, it's a lvalue. – curiousguy Apr 27 '18 at 06:27
  • 1
    @curiousguy this is really helpful!! Thanks for the clarification!! – gchen Apr 27 '18 at 11:54
0

But I'm not so sure about *bptr = dobj2;.

From over.match.oper#tab:over.rel.op.func

Both:

*bptr = dobj2; // ditto
dobj1 = dobj2; // calls implicitly-declared D::operator=(const D&)

are the same in context but represented differently as:

Expression:

a=b

As member function:

(a).operator= (b)
Joseph D.
  • 11,804
  • 3
  • 34
  • 67