views:

90

answers:

6

I have a project where I have a lot of related Info classes and I was considering putting up a hierarchy by having a AbstractInfo class and then a bunch of derived classes, overriding the implementations of AbstractInfo as necessary. However it turns out that in C++ using the AbstractInfo class to then create one of the derived objects is not that simple. (see this question, comment on last answer)

I was going to create like a factory class which creates an Info object and always returns an AbstractInfo object. I know from C# you can do that with interfaces, but in C++ things are a little different it seems.

Down casting becomes a complicated affair and it seems prone to error.

Does anyone have a better suggestion for my problem?

+1  A: 

While generally you can't overload on return types in C++, there is an exception for covariant return types

Example taken from wikipedia:

 // Classes used as return types:
 class A {
 }

 class B : public A {
 }

 // Classes demonstrating method overriding:
 class C {
     A* getFoo() {
         return new A();
     }
 }

 class D : public C {
     B* getFoo() {
         return new B();
     }
 }

Thus eliminating the need for casting.

Pieter
this is not well formed c++.
TokenMacGuy
`extends` - what language was that from? And you want to return a pointer to the newly allocated object. There's no factory facility there either.
Tony
Not a C++ code.
Hemant
Looks like Java to me...
Tony
I tried to fix the sample code. It should now read "C++". Hope that's alright with you, Pieter.
sbi
@sbi as stated it was just an example taken from wikipedia, to illustrate covariant return types, never claimed, nor intended to be C++. But given the question not taking the time to C++ ify the example was indeed a very stupid thing for me to do. So thanks :)
Pieter
+2  A: 

Don't downcast - use virtual methods. Just return the pointer to a base class from the factory and only work through that pointer.

sharptooth
I see... but if you do AbstractInfo* info = new DerivedInfo(), you need to at least let the compiler know which version of the virtual function you need, is that not considered a downcast??
Tony
The version from the most derived class will be called automatically, no downcast needed.
sharptooth
The compiler doesn't need any help at all determining which method to use. that's what `virtual` does. when you call a virtual method on a pointer, the compiler knows that the value could actually be of another, derived type. it examines the object for its type, then looks up the corresponding virtual method.
TokenMacGuy
+5  A: 

You don't require downcasting. See this example:

class AbstractInfo
{
public:
    virtual ~AbstractInfo() {}
    virtual void f() = 0;
};

class ConcreteInfo1 : public AbstractInfo
{
public:
    void f()
    {
        cout<<"Info1::f()\n";
    }
};

class ConcreteInfo2 : public AbstractInfo
{
public:
    void f()
    {
        cout<<"Info2::f()\n";
    }
};

AbstractInfo* createInfo(int id)
{
    AbstractInfo* pInfo = NULL;
    switch(id)
    {
    case 1:
        pInfo = new ConcreteInfo1;
        break;

    case 2:
    default:
        pInfo = new ConcreteInfo2;
    }

    return pInfo;
}


int main()
{

    AbstractInfo* pInfo = createInfo(1);
    pInfo->f();
    return 0;
}
Naveen
+1  A: 
class AbstractInfo
{
  public:
    virtual ~AbstractInfo();
    virtual X f();
   ...
};

class Info_1 : public AbstractInfo
{
    ...
};

class Info_2 : public AbstractInfo
{
    ...
};

AbstractInfo* factory(inputs...)
{
    if (conditions where you would want an Info_1)
        return new Info_1(...);
    else if (condtions for an Info_2)
        return new Info_2(...);
    else
        moan_loudly();
}

If you don't want the factory method to become a single point of maintenance as downstream client code adds Info types, you can instead provide some mechanism for client code to register methods for creation of those derived objects. Check out the Gang of Four's Design Patterns book for creational patterns, or google them.

Tony
A: 

C++ provides polymorphism just as C# does. The language has no special interface-type, but you can emulate that by using a class that only has pure virtual methods. In C# all methods are virtual by default (meaning they are bound at runtime), whereas in C++ you have to declare that explicitly using the virtual-keyword. Also, C# handles all objects using references (as far as I know), whereas in C++ you have to choose between values, pointers or references. In your case, you most likely want your factory to return a pointer to the interface, or even better a smart pointer, so you don't have to worry about memory management.

Space_C0wb0y
A: 

To elaborate / pontificate a little, the "good" time to use an abstract interface (eg: base class with virtual functions) is when substantially all the functionality which will be used on the objects can be contained in virtual functions. If that's the case, you can do what you're proposing easily, and just call the virtual functions on the base class pointer, which will automatically call the most-derived version provided.

If you find yourself needing to downcast often to get at child-class specific functions/data, this approach is probably not optimal for your situation. In that case you may find yourself writing some of the functionality outside the classes, providing multiple implementations for each type, and using some sort of RTTI to help downcast as necessary. This is more messy, but tends to be more common outside of the "academic" or well-isolated usages.

Looks like you've got a lot of good info/advice here in the other answers, though.

Nick