Q:

Qual é a vantagem de se usar uma interface se eu sempre consigo o mesmo comportamento usando simples classes no Delphi?

Antes de mais nada, quero salientar que esta questão NÃO TRATA de comparação entre classes abstratas e interfaces, ela visa descobrir se há alguma vantagem na utilização de interfaces em detrimento da utilização de classes ordinárias e conceitos básicos de OO. A informação acerca de pergunta em duplicidade não se aplica 
Segue o texto da pergunta:
As interfaces sempre foram um assunto um tanto obscuro para mim. Eu simplesmente não consigo achar utilidade para elas no meu dia a dia, mesmo com tantas pessoas dizendo que elas são um recurso poderoso. Tudo que eu faço com interfaces eu consigo fazer com simples herança de classes.
Juntamente com a resposta, seria interessante que alguém propusesse aqui algum problema PRÁTICO que só se resolve com o uso de interfaces. Por favor, que não seja algum problema relacionado às tecnologia COM/COM+ que obrigam as interfaces "simplesmente porque sim". O melhor exemplo seria algo simples, usando classes reais e uma explicação do porquê o problema só se resolve usando as interfaces, ou no mínimo, se resolve melhor usando elas.
Quero lembrar que a resposta deve levar em conta que se está usando o Delphi para implementar, porque o Delphi pode possuir classes com métodos virtuais e abstratos que não são interfaces, mas se comportam como tal.

A:

Nem tudo que se faz com interfaces, é possível de ser feito com classes. Uma interface é um contrato, não implica qualquer implementação, já uma classe implica uma implementação, ainda que tenha possibilidade de se usar métodos abstrados e virtuais. Uma interface, portanto, pode ser implementada por qualquer classe, em qualquer hierarquia de classes. Já usar apenas classes implicaria que absolutamente TODOS os objetos envolvidos em alguma operação, necessariamente teriam que pertencer à mesma hierarquia de classe.
Geralmente falando:

Herança implica uma relação "ser" (Funcionário é uma Pessoa)
Interface implica uma relação "pode" (Bitmap pode ser desalocado)

Vou responder sem código de implementação (e talvez com uma sintaxe não 100%) para evitar limitar essa resposta ao Delphi, já que sua pergunta é de uso geral para Orientação ao Objeto.
Imagine que você queira implementar uma forma padronizada para serialização de classes para JSON (ou outro formato qualquer). Se você escolher o caminho da herança terá que, obrigatoriamente, forçar que todos os objetos herdem de um mesmo pai. Isso pode ser indesejável, pois introduzirá um acoplamento entre classes com nenhuma relação entre si. Sua hierarquia de objetos deixará de ser pura, podemos dizer. 
Com classes você teria que ter algo assim:
TSuperClassePaiDeTodos : class
published
    function Serializa : String; virtual; abstract;
end;

TUsuario : class(TSuperClassePaiDeTodos) 
published
    function Serializa : String; override;
end;

TLancamentoFiscal : class(TSuperClassePaiDeTodos)
published
    function Serializa : String; override;
end;

TOperadorMatematico : class(TSuperClassePaiDeTodos)
published
    function Serializa : String; override;
end;

Não existe nenhuma relação entre um Lançamento Fiscal e um Usuário (muito menos um operador matemático que você usa, por exemplo, para interpretar expressões dinâmicas criadas pelo usuário), mas usar herança de classes para forçar "um contrato" (ou uma interface), nesse caso nos obrigou a criar uma relação entre essas classes: todas herdam da mesma classe pai e exigem a implementação do método Serializa.
Isso não seria tão grave, uma vez que queremos que todas sejam serializáveis. Mas e se precisarmos de algum comportamento que seja comum entre algumas classes, mas não em outras (imagine que você tenha centenas de classes, divididas em várias hierarquias, todas herdando da classe pai). O que você faria nesse caso? Você iria lá na classe "pai de todos" e adicionaria um método abstrato. O efeito cascata disso é enorme: todas as suas centenas de classes teriam que implementar esse novo método, mesmo aquelas que não precisam dele.
Imagine que queiramos adicionar, por exemplo, funcionalidade de auditoria, que é comum à vários objetos, mas não todos. Por exemplo, faz sentido um Usuário e um Lançamento Contábil serem auditados, mas nunca um Operador Matemático. Como resolver isso de forma elegante? 
Você poderia simplesmente fazer uma implementação vazia do método da auditoria, mas isso já começa a soar como uma gambiarra. E ainda pode ter efeitos não esperados se o código que chama o método de auditoria está esperando algum comportamento específico de quem implementa esse contrato/interface/função, como, por exemplo, atualizar algum contador, alocar alguma área de memória, etc. Você acaba tendo um objeto que implementa o método de auditoria na teoria, mas não de fato. Soa mal, não?
Você poderia tentar modificar a hierarquia de classes para descobrir uma forma de colocar um pai comum somente entre as classes que precisem de auditoria. Isso ainda é fácil com apenas três classes: 
TSuperClassePaiDeTodos : class
published
    function Serializa : String; virtual; abstract;
end;

TSofreAuditoria : clas(TSuperClassePaiDeTodos)
published
    procedure Audita: virtual; abstract;
end;

TUsuario : class(TSofreAuditoria)
published
    function Serializa : String; override;
    procedure Audita: override;
end;

TLancamentoFiscal : class(TSofreAuditoria)
published
    function Serializa : String; override;
    procedure Audita: override;
end;

TOperadorMatematico : class(TSuperClassePaiDeTodos)
published
    function Serializa : String; override;
end;

Agora, com uma dezena de classes isso se torna um processo extremamente confuso, com uma centena de classes é inviável. Além disso sua hierarquia de classes já começa a ficar esquisita, difícil de compreender. Em um determinado momento, você perderá o controle. 
E tudo isso porque você está tentando substituir a funcionalidade das Interfaces por uma hierarquia de classes.
Com interfaces você pode garantir que objetos tenham algum, ou alguns métodos em comum, ou seja, sigam um contrato, sem forçar que esses objetos pertençam a uma mesma hierarquia de classes predefinida. Com interfaces você define capacidades que podem ser implementadas por diversas classes não correlacionadas.
O problema que usamos de exemplo pode ser resolvido de forma simples:
ISerializavel : Interface(IInterface)
published
    function Serializa : String; 
end;

IAuditavel : Interface(IInterface)
published
    procedure Audita;
end;

TUsuario : class(TInterfacedObject, ISerializavel, IAuditavel)
published
    function Serializa : String; 
    procedure Audita;
end;

TLancamentoFiscal : class(TInterfacedObject, ISerializavel, IAuditavel)
published
    function Serializa : String; 
    procedure Audita;
end;

TOperadorMatematico : class(TInterfacedObject, ISerializavel)
published
    function Serializa : String; 
end;

Note que removemos toda e qualquer relação indesejável entre as classes. A hierarquia não mais precisa seguir uma definição rígida. E a introdução da funcionalidade de auditoria não exigiu mudanças na hierarquia, nem sua implementação em objetos que não são auditáveis. O Código ficou também bastante mais legível e manutenível. 
Como uma classe pode implementar mais de uma interface, isso se torna uma forma muito eficiente de organizar funcionalidades que sejam comuns entre objetos que não tenham relação entre si, ou seja, que não tenham uma relação "ser" entre si. Mantenha sua hierarquia de classes fortemente cimentada nos conceitos de orientação ao objeto: se um objeto não é, de verdade, da mesma família de outro, não faça deles irmãos, ou pais e filhos! Use agregação ou interfaces.
Vantagens, desvantagens e aplicações
Interfaces são uma forma de especificar um contrato (uma forma padronizada e esperada de interagir com algum objeto), mas classes também definem contratos. É um mito que interfaces sejam obrigatórias para se especificar um contrato, como já vimos, classes podem definir métodos abstratos, os quais precisam, necessariamente, ser implementados nos descendentes. Isso firma um contrato. 
Na minha opinião devemos optar primeiro por classes, uma vez que são mais fáceis de manter do que interfaces. Apenas quando surgirem necessidades que sejam melhor atendidas por interfaces (como o exemplo aqui usado) é que introduziria interfaces. Muitas vezes, ao introduzir interfaces, crio uma classe pai/mãe que fornece uma implementação padrão para tal interface a fim de facilitar sua implementação (mas isso não força que todas as classes que implementem tal interface herdem também dessa classe: elas podem implementar a interface do zero).
O livro .NET Design Framework Guidelines concorda com meu posicionamento e fornece mais alguns argumentos sobre o favorecimento do uso de classes no lugar de interfaces:

Em geral classes são a construção preferida para expor abstrações.
A principal desvantagem de interfaces é que elas são muito menos
  flexíveis do que classes no que concerne a futura evolução de uma API.
  Uma vez que você publique uma interface, seu conjunto de membros está
  congelado para sempre. Quaisquer adições à interface quebrariam tipos
  existentes que implementem aquela interface.
Uma classe nos dá mais flexibilidade. Você pode adicionar membros à
  classes que você já publicou. Desde que o método não seja abstrato (ou
  seja, desde que você forneça uma implementação padrão para o método),
  quaisquer classes derivadas continuarão funcionando sem modificações.
[ . . . ]
Um dos argumentos mais comuns em favor de interfaces é que elas
  permitem separar contrato de implementação. Contudo, o argumento
  assume incorretamente que você não possa separar contratos de
  implementação usando classes. Classes abstratas residindo em um
  assembly (uma Unit, biblioteca ou um componente em Delphi) separado de
  suas implementações concretas é uma ótima forma de alcançar tal
  separação.

Nota: tradução livre feita por mim!
O problema da evolução de APIs pode ser visto na bagunça generalizada que são as APIs de Direct X. Você tem um monte de interfaces, com o mesmo nome, seguidas de um número apenas porque as interfaces já publicadas não poderiam ser modificadas com as novas funcionalidades introduzidas à cada versão do Direct X. Agora temos IDirect3D7, IDirect3D8, IDirect3D9, etc.
No caso do Direct X, como as interfaces precisam ser usadas por diferentes linguagens de programação, seria muito difícil publicar essa funcionalidade sem recorrer ao uso de interfaces, mas esse mesmo problema pode acontecer numa API nossa se não tomarmos cuidado de usar classes onde classes são mais pertinentes do que interfaces!
Portanto, use interfaces quando são a ferramenta correta para o caso. Toda vez que você tiver um contrato que se aplique a classes totalmente independentes (não correlatas) as interfaces serão a melhor solução para o caso, evitando que você engesse sua hierarquia de classes forçando heranças artificiais. 
Use interfaces também quando precisar implementar herança múltipla (ou algo similar) em linguagens que não forneçam suporte para tal.
Use, também, interfaces quando a imutabilidade for um efeito desejado: você não quer que aquele contrato possa ser modificado no futuro, e sim que um novo contrato precise ser firmado (uma nova interface introduzida) em caso de surgir novas funcionalidades.
Evite, à todo custo, a generalização prematura, pois isso é, tal qual a otimização prematura, uma perda de tempo na maioria das vezes. Projete bem sua estrutura de objetos, mas apenas generalize quando perceber a real necessidade. Lembre-se que é possível (e desejável) introduzir generalizações durante refatoramentos, e isso, inclusive é o indicado nos paradigmas Agile, XP, enfim, os mais modernos. 

