What's wrong with the code?
You're invoking Undefined Behavior here:
Foo* bar = &Bar();
This code actually shouldn't compile, but at least two compilers accept it (the Microsoft Visual Studio compiler, and the Intel C++ compiler).
This executes the following steps:
- Create a temporary instance of Bar
- Take the address of that instance
- Assign the address to the variable
bar
- Destroy that instance
When, on the next line, you try to use bar, the temporary instance has already been destroyed. This invokes the undefined behavior.
How do we fix the Undefined Behavior?
What you're missing is a new:
// Old way; prone to memory leaks
Foo* bar = new Bar();
Even better, use a unique_ptr:
// New way; bar acts like a pointer, and it gets automatically deleted
// at the end of the scope
std::unique_ptr<Foo> bar = std::make_unique<Bar>();
This will allow you to use bar safely:
std::cout << "name=" << bar->name << " number = " << bar->number << '\n';
Why is it printing "foo default value" instead of "here I want other value"?
Variables aren't virtual. That means that if you use bar->name, because bar is a pointer to Foo, this refers to name as it's defined in Foo.
In order to fix this, we need to use virtual member functions:
struct Foo {
virtual std::string getName() {
return "I am foo.";
}
// We need to have this, so that the destructor is called correctly.
virtual ~Foo() = default;
};
struct Bar {
std::string getName() override {
return "I am actually bar.";
}
};
Now, things work as intended:
std::unique_ptr<Foo> bar = std::make_unique<Bar>()
std::cout << bar->getName() << '\n'; //Prints "I am actually bar."
When, on the next line, you try to use bar, the temporary instance has already been destroyed. This invokes the undefined behavior.
Instead you should do:
std::unique_ptr<Foo> bar (new Bar());