Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning abstract type in base class

In a design of a class hierarchy, I'm using an abstract base class that declares various methods that the derived classes would implement. In a sense, the base class is as close to an interface as you can get in C++. However, there is an specific issue. Consider the code below which declares our interface class:

class Interface {
public:
    virtual Interface method() = 0;
};

class Implementation : public Interface {
public:
    virtual Implementation method() { /* ... */ }
};

Of course, this wouldn't compile, because you cannot return an abstract class in C++. To get around this problem I'm using the following solution:

template <class T>
class Interface {
public:
    virtual T method() = 0;
};

class Implementation : public Interface<Implementation> {
public:
    virtual Implementation method() { /* ... */ }
};

This solution works and is all fine and dandy, however, to me, it doesn't look very elegant, because of the redundant bit of text which would be the parameter for interface. I'd be happy if you guys could point our any other technical issues with this design, but that is my only concern at this point.

Is there any way to get rid of that redundant template parameter? Possibly using macros?

Note: The method in question has to return an instance. I'm aware that if method() returned a pointer or a reference, there would be no issue.

like image 430
Zeenobit Avatar asked Oct 28 '11 00:10

Zeenobit


People also ask

Can you return an abstract class?

No, a abstract type can't be returned directly , You should return a subclasses of abstract classes .

Can abstract class be a base class?

An abstract class is a class that is designed to be specifically used as a base class. An abstract class contains at least one pure virtual function. You declare a pure virtual function by using a pure specifier ( = 0 ) in the declaration of a virtual member function in the class declaration.

Can you inherit an abstract base class?

NO. Abstract methods(defintion) are overridden by base class' overriding methods.

Should base class always be abstract?

Yes, it is reasonable and beneficial to mark explicitly as abstract a base class that should not be instantiated -- even in the absence of abstract methods. It enforces the common guideline to make non-leaf classes abstract. It prevents other programmers from creating instances of the class.


2 Answers

Interface::method() cannot return an Interface instance without using a pointer or reference. Returning a non-pointer, non-reference Interface instance requires instantiating an instance of Interface itself, which is illegal because Interface is abstract. If you want the base class to return an object instance, you have to use one of the following:

A pointer:

class Interface
{
public:
  virtual Interface* method() = 0;
};

class Implementation : public Interface
{
public:
  virtual Interface* method() { /* ... */ }
};

A reference:

class Interface
{
public:
  virtual Interface& method() = 0;
};

class Implementation : public Interface
{
public:
  virtual Interface& method() { /* ... */ }
};

A template parameter:

template<type T>
class Interface
{
public:
  virtual T method() = 0;
};

class Implementation : public Interface<Implementation>
{
public:
  virtual Implementation method() { /* ... */ }
};
like image 188
Remy Lebeau Avatar answered Oct 04 '22 15:10

Remy Lebeau


While you can't return by value for obvious reasons, it's entirely OK to return pointers or references -- this is called "covariant return type", and it is a valid form of virtual function overriding:

struct Base { virtual Base * foo(); }
struct Derived : Base { virtual Derived * foo(); }

The point is that Derived::foo() is a genuine override, and not a base-hiding overload, because Derived* is is a pointer to a derived class of Base. The same applies to references.

In other words, if you have a Base * p, and you call p->foo(), you can always treat the result as a pointer to Base (but if you have additional information, such as that your class is in fact Derived, then you can use that information).

The opposite composition order, i.e. "contravariant argument types", is not allowed as part of C++.

like image 23
Kerrek SB Avatar answered Oct 04 '22 17:10

Kerrek SB