-4

I try understand what's going on here, why bar doesn't have default value for name property

#include <string>

struct Foo
{
    std::string name = "foo default value";
    std::size_t number = 23;
};

struct Bar : public Foo
{  
    std::string name = "here i want other value";
};

int main(int argc, char * argv[])
{
    Foo foo;
    std::cout<<"name="<< foo.name << " number=" << foo.number << std::endl;
    Foo * bar = &Bar();
    std::cout<<"name="<< bar->name << " number=" << bar->number << std::endl;
    return 0;
}

output:

name=foo default value number=23
name= number=23 // why name is empty string?

I assume that's default generated constructos are involed in final result. But can't get it right in my mind. Can someone explain what sorcery compiler does here?

Sonny D
  • 897
  • 9
  • 29

1 Answers1

3

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()); 
Community
  • 1
  • 1
Alecto Irene Perez
  • 10,321
  • 23
  • 46
  • *"invoking Undefined Behavior"* It shouldn't compile to begin with, so it's not UB. – HolyBlackCat Aug 05 '19 at 19:16
  • 2
    Most compilers correctly recognize that the code takes the address of a temporary, and they don't compile it, but (unfortunately) both the Intel C++ compiler and the MSVC compiler accept the code. – Alecto Irene Perez Aug 05 '19 at 19:20
  • You haven't mentioned the simpler way of having `Bar`'s constructor pass a value for `name` an appropriate constructor in `Foo`, while eliminating the `name` in `Bar`. – 1201ProgramAlarm Aug 05 '19 at 19:36
  • @J.AntonioPerez yesterday I don't have time for thanks. Thank you so much for such good explanation. I'm rookie to c++, and have backgrounds in web languages (its shame to admit it :D :) ). That's why I do this stupid things in c++. – Sonny D Aug 06 '19 at 11:04
  • I hope I was able to help! If you want to write more generic code, you should also take a look at using templates. They're a lot more powerful than generics are in other languages (for example, in java you can't do `T x = new T();`, but that's trivial in C++ as `T x = T();` or as `T* x = new T();`). Templates are useful because they're faster than using virtual function calls and inheritance, and you don't have to specify an interface when writing a template – Alecto Irene Perez Aug 06 '19 at 17:18