1

I have a class objects and astruct objects in C++. The struct is responsible for populating the class with data from a CSV file. So the extension of this was that when I created a derived class, I also created a derived struct that would correctly fill this similar, but different derived class.

struct BaseStruct {
    double var = 0;
    vector<double> vectorA;
    virtual BaseClass^ generateClass() {return gcnew BaseClass(this->var, this->vectorA);}
};
struct DerivedStruct : BaseStruct {
    vector<double> vectorB;
    virtual BaseClass^ generateClass() override {return gcnew ChildClass(this->var, this->vectorA, this->vectorB);}
};

The structs are then used by another object that does file reading, and returns the polymorphic struct to the user;

BaseStruct FileReader::GetSetupStruct(String^ parameter)
    {
        BaseStruct retval; //Struct to be passed back
        retval = (boolLogicCondition) ? BaseStruct() : DerivedStruct(); //Should return correct type of struct
        return retval;
    }

However, when I attempt to use the code below, by referring to it as a base class, it automatically reverts to a base class (losing the additional vectorB attribute) and its polymorphic nature.

I suspect it loses its derived status because a) its type in the local variable window changes when I return from the ternary operator b) setupStruct.generateClass() only ever executes the base class method

BaseStruct setupStruct = FileReader::GetSetupStruct(parameter);//Returns struct - type should depend on parameters
    Signal^ mySignal = setupStruct.generateClass(); //Should run either derived or base method

How can I use these two structs and generate the correct type at run time, but maintain the polymorphism nature without it being upcasted to the base type?

1 Answer 1

1

In this code:

BaseStruct retval; //Struct to be passed back
retval = (boolLogicCondition) ? BaseStruct() : DerivedStruct();
  • The choice operator produces a value, not a reference.

  • The assignment to retval of type BaseStruct, anyway slices the result to BaseStruct.


Re

How can I use these two structs and generate the correct type at run time, but maintain the polymorphism nature without it being upcasted to the base type?

… one way to get polymorphic behavior is to return a pointer to a factory instance, instead of returning by value:

auto FileReader::GetSetupStruct(String^ parameter)
    -> std::unique_ptr<BaseStruct>
{
    if( boolLogicCondition )
    {
        return std::make_unique<BaseStruct>();
    }
    else
    {
        return std::make_unique<DerivedStruct>();
    }
}

Disclaimer: off the cuff code not even glanced at by a compiler.


In other context the choice operator can produce a reference. For example, with two variables a and b of the same type, you can do

auto* p = &(condition? a : b);

But in the code above the sub-expressions to choose from are both rvalue expressions, or more informally, “value” expressions that you could not apply the built-in & address operator to.

2
  • Could you explain your choice of code please? I understand that my code slices the result back to the base class, but am unsure how your code doesnt and how you have used the auto keywords along with the make_unique methods? (or even some examples online I can look at!) Thanks very much!
    – davidhood2
    Commented Jan 9, 2017 at 19:59
  • 1
    Well, for the GetSetStruct function auto is just the modern (my preferred) declaration syntax, just as the curly braces convention is my preferred one rather than the one you used. So you can just replace all that with your preferred way of writing the code. C++14's make_unique<T>() is roughly equivalent to unique_ptr<T>( new T ), but it's shorter and it's safer for the situation where you would otherwise have two or more new expressions in an argument list. In the last example I could have said that the type of a was int and then int* p instead of auto* p. Maybe more clear? Commented Jan 10, 2017 at 4:38

Not the answer you're looking for? Browse other questions tagged or ask your own question.