That's composition, not inheritance - and yes, with composition you can essentially emulate inheritance. And if the class implements the interface of the encapsulated object, then things start looking like some kind of a decorator pattern.
Except you wouldn't be having any implementation code in IBird. An interface should be purely abstract. Making a New instance of what's supposed to be an interface, makes the class no longer be an interface: now it's just another class exposing a default interface that any other class can implement, and the I prefix becomes rather confusing:
Set pBird = New IBird
It's rather weird that the client code now needs to wonder whether they want that bird to chirp FromInstance or FromInterface - these are very "meta" identifiers that make things not work like inheritance.
If we had a Crow : Bird where Bird had this implementation for IBird.Chirp:
public virtual string Chirp() => "Chirp!";
...and then Crow had this:
public override string Chirp() => "Craaaw!";
Then which method is invoked depends on what the runtime type is - this should feel pretty obvious:
IBird bird1 = new Bird();
bird1.Chirp(); // "Chirp!"
IBird bird2 = new Crow();
bird2.Chirp(); // "Craaaw!"
However picture a method that receives an IBird parameter:
public void DoSomething(IBird bird)
{
Debug.Print(bird.Chirp());
}
If bird is a Bird, it prints "Chirp!"; if bird is a Crow, it prints "Craaaw!": the method that gets to run, is the most derived override, which isn't necessarily defined on the most derived type.
Inheritance would allow a GiantCrow : Crow to inherit the Chirp method from Crow and not necessarily override it. And that is what you can't simulate with VBA classes: you are forced to write the equivalent of...
public override string Chirp() => base.Chirp();
...which is technically redundant, and gets very repetitive if you have to do it every time just to get the "base" members visible on your default interface.
Instead of inheriting base members, we actually wrap calls to the encapsulated object. The decorator pattern does exactly that, and gives you a non-intrusive way of extending a VBA class or interface.
A decorator implements the interface it's extending, and encapsulates a private instance of that type. So basically with a decorator the "crow inheritance hierarchy" setup looks like this:
Dim bird As IBird
Set bird = Crow.Create(New BaseBird)
A perhaps more suitable decorator pattern example might be:
Dim repository As IRepository
Set repository = LoggingRepository.Create(BirdRepository.Create(connectionString), New DebugLogger)
Where a BirdRepository is responsible for abstracting the database operations relating to some Birds table (BirdRepository implements IRepository), and where LoggingRepository is a decorator that also implements IRepository, but also wraps an IRepository instance (in this case a BirdRepository) to add its own functionality - something that might look like this:
'@PredeclaredId
Implements IRepository
Private loggerInternal As ILogger
Private wrappedInternal As IRepository
Public Function Create(ByVal internal As IRepository, ByVal logger As ILogger) As IRepository
Dim result As LoggingRepository
Set result.Wrapped = internal
Set result.Log = logger
Set Create = result
End Function
Public Property Get Wrapped() As IRepository
Set Wrapped = wrappedInternal
End Property
Public Property Set Wrapped(ByVal value As IRepository)
If Not wrappedInternal Is Nothing Then Err.Raise 5, TypeName(Me), "Instance is already initialized."
Set wrappedInternal = value
End Property
Public Property Get Log() As ILogger
Set Log = loggerInternal
End Property
Public Property Set Log(ByVal value As ILogger)
If Not loggerInternal Is Nothing Then Err.Raise 5, TypeName(Me), "Instance is already initialized."
Set loggerInternal = value
End Property
Private Function IRepository_SelectAll() As Object
Log.Info "Starting IRepository.SelectAll"
Dim t As Double
t = Timer
Set IRepository_SelectAll = wrappedInternal.SelectAll
Log.Info "IRepository.SelectAll completed in " & Timer - t & " seconds."
End Function
Private Sub IRepository_Delete(ByVal id As Long)
Log.Info "Starting IRepository.Delete(" & id & ")"
Dim t As Double
t = Timer
wrappedInternal.Delete id
Log.Info "IRepository.Delete completed in " & Timer - t & " seconds."
End Sub
Private Sub IRepository_Save(ByVal entity As Object)
'...
wrappedInternal.Save entity
'...
End Sub
'...
A method that is given a IRepository object cannot (and absolutely should not) know whether it's given a plain BirdRepository, a LoggingRepository wrapping a BirdRepository, or a FakeRepository that encapsulates a Collection instead of access to a database table - and this polymorphism is the entire point.
It's one way to extend a type without using inheritance, that VBA can absolutely leverage without bastardizing the pattern too much. But it's not inheritance.
As New IBirdonly to immediately wipe that reference with aNew Crow? Just declareAs IBird.SourceTools.xlato extract the source files from Excel? Or is there functionality in Rubberduck to do that?