0

I want to learn virtual functions. I have made print() in class Base virtual and my program crashes. Why do I have to create the two objects with new?

#include <iostream>

class Base {
    public:
        virtual void print();
};

void Base::print() {
    std::cout << "Base print method" << std::endl;
}

class Derived : public Base {
    public:
        void print();
};

void Derived::print() {
    std::cout << "Derived print method" << std::endl;
}

int main()
{
    Base* b; // Base* b = new Base(); runs
    b->print();
    Derived* d; // Derived *d = new Derived(); runs
    d->print();
}
  • 2
    Undefined behavior! dereferencing a pointer without allocating the object first. – Tony Tannous Sep 30 '20 at 08:15
  • Does this answer your question? [What are all the common undefined behaviours that a C++ programmer should know about?](https://stackoverflow.com/questions/367633/what-are-all-the-common-undefined-behaviours-that-a-c-programmer-should-know-a) – Tony Tannous Sep 30 '20 at 08:18
  • 2
    You have a pointer `b`, but *where does it point?* – Some programmer dude Sep 30 '20 at 08:19
  • 1
    your problem is not realted to virtual function. Review the difference between pointers to objects and objects – 463035818_is_not_an_ai Sep 30 '20 at 08:19
  • well ok it is somewhat related to virtual functions, because if `print` wasnt virtual then most probably the code would appear to work, but the mistake would still be the same – 463035818_is_not_an_ai Sep 30 '20 at 08:28
  • 2
    Creating a pointer does not implicitly create an object for that pointer to point at. `Base *b` and `Derived *d` create two unitialised pointers, and do not create any objects for them to point at. Even accessing the value of an ininitialised pointer gives undefined behaviour, let alone trying to dereference it (access the object it points at, or call any member function (i.e. `b->print()`). `Base *b = new Base()` and `Derived *d = new Derived()` fix the problem, because they dynamically create objects, and initialise the pointers so the point at those objects. – Peter Sep 30 '20 at 08:47
  • the problem is not with virtual functions, that part seems fine (maybe you can also use the `override` keyword in the derived class). the problem is that you are using pointers, but you are not associating that pointers to a valid memory area. In order to use pointers you need them to point to something valid, for example allocating it using `new`. So as you already wrote: `Base* b = new Base();` will work. Please note, you are using "new", so you need to "delete" the memory area when you are done. So, in your main, you need to add a call to the delete function when you are done: `delete b;` – crsn Sep 30 '20 at 11:47

4 Answers4

1

Why do I have to create the two objects with new?

You don't have to.

It is a common misunderstanding that you need to dynamically create objects for polymorphism. Often polymorphism is used with dynamically created objects, but it is not strictly necessary to enable polymorphism. You need references or pointers for polymorphism, so eg this will work:

#include <iostream>

class Base {
    public:
        virtual void print();
};

void Base::print() {
    std::cout << "Base print method" << std::endl;
}

class Derived : public Base {
    public:
        void print();
};

void Derived::print() {
    std::cout << "Derived print method" << std::endl;
}

void do_print(Base& b) {
   b.print();
}    

int main()
{
    Base b;
    do_print(b);
    Derived d;
    do_print(d);
}

In your code you have only pointers in main but you never create objects. Your pointers do not point to objects, the are uninitialized. Dereferencing those pointers invokes undefined behavior.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
0

Because Base* b does not create the object as long as you don't tell it to do so by adding the new Base(). Therefore dereferencing your pointer to the print function has no valid target.

po.pe
  • 1,047
  • 1
  • 12
  • 27
0

Base* b; doesn't create an object, but creates a pointer of type Base* with automatic storage duration. The behaviour on dereferencing that pointer is undefined.

Base b or new Base() actually create objects. The former has automatic storage duration, the latter has dynamic storage duration.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
0

You are using pointers, so they need to point to something.

You're basically saying: "hey, this b variable points to a Base object", but you never create a base object (with new), so it points to random memory, and crashes when you try and treat that memory as a Base object.

GazTheDestroyer
  • 20,722
  • 9
  • 70
  • 103