1

I have a base class that includes a virtual method and a cast operator:

class Base {
public:
    Base() {}
    operator int() const { return getInt(); }
protected:
    virtual int getInt() const { return 0; }
}

Then I have two derived classes that override the virtual method:

class Derived1 {
public:
    Derived1() : Base() {}
protected:
    virtual int getInt() const override { return 1; }
}

class Derived2 {
public:
    Derived2() : Base() {}
protected:
    virtual int getInt() const override { return 2; }
}

Then I have a helper function:

Base helper(const bool flag) {
    if (flag)
        return Derived1();
    else
        return Derived2();
}

The intention of that helper function is to be used like:

int one = helper(true); // I expect "one" to be 1
int two = helper(false); // I expect "two" to be 2

But both one and two contain 0. I have no idea how to resolve this. Is the cast operator getting called before the Derived classes are fully constructed? My environment is VS2013.


Suggested fix (in my case, after answers)

I ended up turning the helper function into a class which stores Deriveds as members and returning a reference to them (which I believe is actually a better design since on each [] call a Derived does not get constructed / allocated):

class Helper {
public:
    Helper();
    const Base& get(const bool flag) const {
        if (flag)
            return mDerived1;
        else
            return mDerived2;
    }
private:
    Derived1    mDerived1;
    Derived2    mDerived2;
}

Side note

Accepted answer suggests that the gist of the question is thinking about everything as in references (like Python) and that is true. This issue came up as a part of a bigger system design which allows access to results returning from a SQLite database with a Python like syntax in C++. Chaining square brackets like: mData[0][1].

Sepehr
  • 2,051
  • 19
  • 29

1 Answers1

3

Your helper function returns Base by value, which slices off any derived-ness of the object you created inside the function, causing the virtual method to call the base version.

EDIT: I saw this had been marked duplicate but the duplicate, while explaining the problem, doesn't seem to clearly provide a nice solution to this specific problem.

The gist of the answer is that you're probably used to a language like Python or Java where everything is references (and I make the opposite mistake when using those languages). In C++ everything is by value unless you specify everything, and when returned by value the slicing problem comes forward.

What you want to do is allocate the appropriate derived type on the heap, and return a smart pointer to that object from your helper function. The smart pointer will make sure you don't leak memory, and by returning as a pointer instead of by value, you make sure that polymorphism is still active in your program.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • is there a solution to it? if I make `getInt` in `Base` pure virtual that gives me a compile error which is expected. I have tons of those Derived classes in my code. – Sepehr Oct 29 '14 at 20:21
  • You'd have to return an `std::unique_ptr` for example, then do `int one = *(helper(true));`. You can only be polymorphic with pointers and references, not with values. – cdhowie Oct 29 '14 at 20:23