Ref cursors are a special type of cursors where the query is not defined beforehand. Instead, the cursor is defined as a shell or a placeholder and the query is passed during the runtime. Here is an example of a ref cursor:
  1  DECLARE
  2     TYPE ty_bookrefcur IS REF CURSOR;
  3
  4     cu_bookcur   ty_bookrefcur;
  5     rec_books    books%ROWTYPE;
  6     l_title      books.title%TYPE;
  7     l_author     books.author%TYPE;
  8  BEGIN
  9     OPEN cu_bookcur FOR
 10        SELECT *
 11          FROM books;
 12
 13     FETCH cu_bookcur
 14      INTO rec_books;
 15
 16     CLOSE cu_bookcur;
 17
 18     DBMS_OUTPUT.put_line ('Book is ' || rec_books.title);
 19
 20     OPEN cu_bookcur FOR
 21        SELECT title
 22          FROM books;
 23
 24     FETCH cu_bookcur
 25      INTO l_title;
 26
 27     DBMS_OUTPUT.put_line ('Title is ' || l_title);
 28
 29     CLOSE cu_bookcur;
 30
 31     OPEN cu_bookcur FOR
 32        SELECT author
 33          FROM books;
 34
 35     FETCH cu_bookcur
 36      INTO l_author;
 37
 38     DBMS_OUTPUT.put_line ('Author is ' || l_author);
 39* END;
A generic cursor, cu_bookcur, is defined in line 4. In line 9, I have assigned the query "SELECT * FROM books". Later, in line 20, the same cursor is used to execute the query "SELECT select FROM books". This technique is very useful when you don't know the exact query while writing the code. Instead of creating a plethora of cursors for all possible queries, you can define a simple ref cursor and use it to fetch any query on that table.
If you want to make sure the ref cursor returns a specific datatype, define it as "strong" one. Example:
TYPE ty_bookrefcur IS REF CURSOR
        RETURN books%ROWTYPE;
Here the return type is always the record of the table BOOKS. This is useful when you know that the return from the cursor must be all the columns; but the predicate (the "WHERE" clause is different and used at the runtime). Here is an example:
  1  DECLARE
  2     TYPE ty_bookrefcur IS REF CURSOR
  3        RETURN books%ROWTYPE;
  4
  5     cu_bookcur   ty_bookrefcur;
  6     rec_books    books%ROWTYPE;
  7     l_title      books.title%TYPE;
  8     l_author     books.author%TYPE;
  9  BEGIN
 10     OPEN cu_bookcur FOR
 11        SELECT *
 12          FROM books
 13         WHERE title LIKE '%PL/SQL%';
 14
 15     FETCH cu_bookcur
 16      INTO rec_books;
 17
 18     CLOSE cu_bookcur;
 19
 20     DBMS_OUTPUT.put_line ('Book is ' || rec_books.title);
 21
 22     OPEN cu_bookcur FOR
 23        SELECT *
 24          FROM books
 25         WHERE title LIKE '%Security%';
 26
 27     FETCH cu_bookcur
 28      INTO rec_books;
 29
 30     CLOSE cu_bookcur;
 31
 32     DBMS_OUTPUT.put_line ('Book is ' || rec_books.title);
 33* END;
In line 10, I opened the generic cursor to select titles of PL/SQL and in line 22, I used the same generic cursor to get the titles related to Security. I didn't need to open a new cursor.