0

I have a function that returns object of abstract class.

AbstractClass some_function(int argument);

I have an assumption that if argument == 1 then some_function should return object of DerivedClassOne and if argument == 2 it should be DerivedClassTwo. I want to check these assumptions with a simple unit test.

What's the best (simple, readable, reliable and independent of any third-party libraries and tools) way to check that?

Max Yankov
  • 12,551
  • 12
  • 67
  • 135
  • 2
    If the return type is `AbstractClass` then the returned object will always be `AbstractClass`. – juanchopanza Mar 10 '15 at 22:47
  • `DerivedClassOne* derivedOne = dynamic_cast(result);` If result is not DerviedClassOne, then derivedOne will be nullptr. And you need to change your function to return a pointer to AbstractClass. – Tony J Mar 10 '15 at 22:49

2 Answers2

1

Use dynamic_cast, which will result in a NULL pointer if the object isn't of the expected subclass. From Wikipedia:

int main()
{
    Base* basePointer = new Derived();
    Derived* derivedPointer = NULL;

    // To find whether basePointer is pointing to Derived type of object
    derivedPointer = dynamic_cast<Derived*>(basePointer);

    if (derivedPointer != NULL)
    {
        std::cout << "basePointer is pointing to a Derived class object"; // Identified
    }
    else
    {
        std::cout << "basePointer is NOT pointing to a Derived class object";
    }

    // Requires virtual destructor 
    delete basePointer;
    basePointer = NULL;

    return 0;
}
Throw Away Account
  • 2,593
  • 18
  • 21
1

In your example, some_function() is returning an AbstractClass by value, which means the returned object gets sliced and will always be just a AbstractClass by itself. Polymorphism only works with pointers and references. Either way, you can use dynamic_cast for your validation check.

For example:

AbstractClass* some_function(int argument);

...

AbstractClass *obj;

obj = some_function(1);
if (dynamic_cast<DerivedClassOne*>(obj) != NULL)
    // returned the correct type...
else
    // returned the wrong type...

obj = some_function(2);
if (dynamic_cast<DerivedClassTwo*>(obj) != NULL)
    // returned the correct type...
else
    // returned the wrong type...

Or:

AbstractClass& some_function(int argument);

...

try {
    dynamic_cast<DerivedClassOne&>(some_function(1));
    // returned the correct type...
}
catch (const std::bad_cast&) {
    // returned the wrong type...
}

try {
    dynamic_cast<DerivedClassTwo&>(some_function(2));
    // returned the correct type...
}
catch (const std::bad_cast&) {
    // returned the wrong type...
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thanks! Coming from C# (mostly), I didn't grasp the whole difference about returning values by value, reference and pointer. – Max Yankov Mar 11 '15 at 08:16
  • "Which means the returned object gets sliced" left me confused. Can you please explain what it means and how it works, exactly? – Max Yankov Mar 11 '15 at 18:44
  • 1
    See [What is object slicing?](http://stackoverflow.com/questions/274626/what-is-object-slicing) – Remy Lebeau Mar 11 '15 at 18:58
  • Thanks again. After reading this, and a lot of other resources, I came up with a new question as a follow-up: http://stackoverflow.com/questions/28995502/how-to-properly-implement-creation-and-allocation-of-a-list-of-objects-known-o – Max Yankov Mar 11 '15 at 19:21