12

What does it mean when there is a reference to an abstract class? I found it in code and I can't understand it.

I thought that an abstract class can't be instantiated. How can you give it a reference?

Johan
  • 74,508
  • 24
  • 191
  • 319
lital maatuk
  • 5,921
  • 20
  • 57
  • 79

4 Answers4

18

A reference to an abstract class is just like a pointer to an abstract class: it needs to reference an object of some non-abstract subclass of the abstract class. You can use a reference like that to call virtual methods on the referenced class using the . syntax, in a way similar to a pointer to an interface in Java.

Jeremiah Willcock
  • 30,161
  • 7
  • 76
  • 78
15

An abstract class is designed to be derived from. The Liskov substitution principle roughly states that anything that uses the abstract parts of types derived from an abstract base should work equally well using the base polymorphically. That means a reference or pointer to the base should be used.

Johann Gerell
  • 24,991
  • 10
  • 72
  • 122
  • 7
    +1 for linking it to Liskov substitution principle. Such valuable hints guide newbies to explore in to the deeper realms of software designing/programing resulting in more competent colleagues in the adjacent cubicles :) – Alok Save Feb 16 '11 at 17:20
  • 2
    @Als: +1 for realizing the longer-term upside of understanding Liskov. ;-) – Johann Gerell Feb 16 '11 at 21:00
7
class Abstract
{
public:
  virtual void foo() = 0;
};

class Implementation : public Abstract
{
public:
  void foo() { std::cout << "Foo!" << std::endl; }
};

void call_foo(Abstract& obj) { obj.foo(); } 

int main()
{
  Abstract *bar = new Implementation();

  call_foo(*bar);

  delete bar;
}

bar is a pointer to an abstract class. It can be dereferenced using the * operator and passed as a reference into call_foo, because that is what call_foo is asking for (Abstract* would be asking for a pointer, whereas Abstract& is asking for a reference).

In the above, the reference to the abstract class is passed, and when foo() is called using the . notation (instead of the pointer -> notation), it prints Foo!, because that is what the Implementation does.

Hope this helps.

James
  • 5,355
  • 2
  • 18
  • 30
  • Of course you don't even need to create a pointer here. You can happily replace Abstract *bar = new Implementation(); with Abstract &bar = Implementation(); or even Implementation bar; – DanDan Feb 16 '11 at 16:45
  • In this case, yes, but I was just displaying the differences / similarities between pointers and references. :) – James Feb 16 '11 at 16:48
4

References in c++ behave (almost) like hidden pointers. In particular, the same polymorphic behavior you can get with a pointer, you can achieve it with a reference. That is, the following are (almost) equivalent

int *i = &a;
int &j = a;

assuming a was an integer defined somewhere in the previous lines. Following occurrences of the reference j, are perfectly equivalent to occurrences of (*i). The main difference is that a reference doesn't give you the pain of memory management, while a pointer does (it is your responsibility to handle new(s) and delete(s)). Also, a pointer doesn't have to point to something, while a reference can't exists if it's not referring to anything (1). Other than that, you can consider them to behave the same way.

Therefore, it's absolutely legal to have a reference to an abstract object. You will find it often in functions signatures, where the polymorphic behavior can be achieved either with references or pointers. But references give a lighter syntax, like the following piece of code shows

A a;
A* ptr = &a;
A& ref = a;
ref();
ptr->operator()();
(*ptr)();

assuming the class A overloads operator ().

(1) Well, you can have dangling references, just like pointers:

int* a = new int(1);
int& b = *a;
delete a; // et-voila, b is now dangling.

but they cannot be created without assigning something they can refer to.

bartgol
  • 1,703
  • 2
  • 20
  • 30