0

I have the following code snippet:

#include <iostream>
#include <typeinfo>
using namespace std;

class A{
public:
    int x;
    A(int i = 0): x(i) {}
    A minus(){
        return 1 - x;
    }
    virtual void print(){
        cout << x << "\n";
        cout << "Base print\n";
    }
};

class B: public A{
    int y;
public:
    B(int i = 0) {x = i;}
    void print(){
    cout << x << "\n";
    cout << "Derived print!\n";
    }
   };

int main(){
    A* p1 = new B(18);
    *p1 = p1->minus();
    p1->print();

    return 0;
}

The output is:

-17
Derived print!

I know where -17 comes from. It does upcasting and A* p1 = new B(18) and makes p1 point to a derived object with x value of 18. *p1 = p1->minus make the object that p1 points to be an A(-17) /// cause 1 -18 = -17. My question is, where does the second line come from ? If p1 points to an A object after the *p1 = p1->minus(), why does p1->print() not print "Base print" ?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 2
    Assigning a `A` to a `B` doesn't change the dynamic type of the `B` to `A`. Once you `new B` it is impossible to change the type of that object by any means. – François Andrieux Jun 11 '21 at 15:00
  • 2
    `p1` still points to a `B`, `*p = someA;` just assigns the `A`'s part. – Jarod42 Jun 11 '21 at 15:00
  • 1
    Assigning a base object to a derived object can lead to [object slicing](https://stackoverflow.com/questions/274626/what-is-object-slicing), beware. – François Andrieux Jun 11 '21 at 15:01
  • @alexMcKenzie You explicitly called the virtual function print p1->print(); The pointer p1 still [points to an object of the type B. – Vlad from Moscow Jun 11 '21 at 15:02
  • @FrancoisAndrieux So what does ```*p1 = p1->minus()``` really do ? How is the copy really made between ```*p1``` that is a base pointer that points to a derived and ```p->minus()``` that is a pure base object ? –  Jun 11 '21 at 15:03
  • @alexMcKenzie *"between `*p1` that is a base pointer"* -- no, `*p1` is an object, not a pointer. The pointer is `p1` (no `*`) and you are not assigning a new value to `p1`. – JaMiT Jun 11 '21 at 15:08
  • @alexMcKenzie `*p1 = p1->minus()` copy assigns (copies the value of) the value of `p1->minus()` to `*p1`. Since `minus()` returns an `A` it will just copy the `A` portion, so it just assigns `p1->x` the value of `p1->minus().x`. `p1` still points to the same, original `B` and only the `x` member was (potentially) changed by the expression. – François Andrieux Jun 11 '21 at 16:11

1 Answers1

4

You created an object of the type class B

A* p1 = new B(18);

So the pointer p1 will point to this object until it (the pointer) will be reassigned.

In this statement

*p1 = p1->minus();

the dynamically created object of the type class B was not deleted. Only its sub-object of the type class A was changed using the implicitly defined by the compiler copy assignment operator of the class A and the pointer p1 still points to the same object of the type class B.

Thus in this statement

p1->print();

there is called the virtual function of the object of the type class B that by the way should be declared in the class B at least like

void print() override
{
    //..
}

Pay attention to that you should declare a virtual destructor in the class A. For example

virtual ~A() = default;

And before exiting main you should delete the dynamically allocated object.

delete p1;
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335