Search code examples
c++ooppolymorphismconditional-statementsinclusion

What do conditionals do to polymorphic objects in C++? (inclusion polymorphism)


I ran into an interesting error and I'm pretty sure it has to do with inclusion polymorphism in the context of conditional statements.

The highlights of the example are as follows:

   ClassParent *parentPointer; //Declare pointer to parent

   if(condition){
       ClassChild1   = mychild; //Declare child1 object
       parentPointer = *mychild;//Parent pointer points to child
   }

   if(!condition){
       ClassChild2   = mychild; //Declare child2
       parentPointer = *mychild;//Parent pointer points to child2  
   }

   cout << *parentPointer; //What will this point to???

As should be clear, the conditional statements make *parentPointer variable in the last line.

My whole function looks like this: (Note where it crashed)

    void PosApp::addItem(bool isPerishable) {
        Item *refitem;

        if (isPerishable) {
            Perishable myitem;
            std::cout   << "Enter the following: "  << std::endl
                        << "Sku: "                  << std::endl
                        << "Name:"                  << std::endl
                        << "Price: "                << std::endl
                        << "Taxed: "                << std::endl
                        << "Quantity: "             << std::endl
                        << "Expiry date: "          << std::endl;

            std::cin    >> myitem;
            refitem = &myitem; //Item now implements inclusion polymorphism,  be aware of dynamic/static types (dynamic is item, static Perishable)
        }

        if (!isPerishable) {
            NonPerishable myitem;
            std::cout   << "Enter the following: "  << std::endl
                        << "Sku: "                  << std::endl
                        << "Name:"                  << std::endl
                        << "Price: "                << std::endl
                        << "Taxed: "                << std::endl
                        << "Quantity: "             << std::endl;

            std::cin    >> myitem;
            refitem = &myitem; //Item now implements inclusion polymorphism,  be aware of dynamic/static types (dynamic is item, static NonPerishable)


        }

        if (cin.fail()) {//The inclusion polymorphism allows me to call this block only once regardless of persh/non-perishable
            cin.clear();
            cin.ignore(2000, '\n');

            //CRASH POINT***********
            cout << "Error: " << *refitem << endl;//Be aware of early/late binding, the write/dowrite must be child calls, not parent.
        }


    }

Now the very interesting thing, is when removed the if() on cin.fail and forced an error in the input, it works. The code looks like this now:

    void PosApp::addItem(bool isPerishable) {
        Item *refitem;


        if (!isPerishable) {
            NonPerishable myitem;
            std::cout   << "Enter the following: "  << std::endl
                        << "Sku: "                  << std::endl
                        << "Name:"                  << std::endl
                        << "Price: "                << std::endl
                        << "Taxed: "                << std::endl
                        << "Quantity: "             << std::endl;

            std::cin    >> myitem;
            refitem = &myitem; //Item now implements inclusion polymorphism,  be aware of dynamic/static types (dynamic is item, static NonPerishable)


            cin.clear();
            cin.ignore(2000, '\n');

            //THIS DOES NOT CRASH NOW
            cout << "Error: " << *refitem << endl;//Be aware of early/late binding, the write/dowrite must be child calls, not parent.



    }

The best answer I could come up with, in terms of the crash, is that somehow when the scope resolved in the first code snippet, the program lost the contents of the pointer.

This question is two fold: Can you implement inclusion polymorphism in the context of conditionals (as shown) and, if not, is this what caused my program to crash?

Note: I did not include the entire program (because it is hundreds of lines) but suffice to say, when I changed to code into the second snippet, the behavior is what should be expected.


Solution

  • Objects with automatic storage are local to the { } braces around them, including the if statement. If you have a pointer to a local, and the object goes out of scope, accessing that pointer is UB.

    Object* ptr;
    if (condition)
    {
        Object obj;
        ptr = &obj;
    } //obj is out of scope
    *ptr; //undefined behaviour
    

    This is what you are doing with setting refitem to point to local objects. Instead, create a Perishable* or NonPerishable* by using new, and when the block ends, assign that pointer to refitem. The polymorphism will work as you expect, the error was just the scope of objects.

    if (!isPerishable)
    {
        NonPerishable* myitem = new NonPerishable(); //dynamic memory
        std::cin >> *myitem;
        refitem = myitem; //refitem is still valid after this scope ends
    }