【问题标题】:Interface implementing multiple interfaces in VBA在 VBA 中实现多个接口的接口
【发布时间】:2020-04-15 17:44:29
【问题描述】:

我想创建一个实现多个接口的接口,然后创建一个实现该接口的类。例如:

IFlyable 模块:

Public Sub Fly()
End Sub

Public Function GetAltitude() As Long
End Function

ISwimmable 模块:

Public Sub Swim()
End Sub

Public Function GetDepth() As Long
End Function

IFlySwim 模块:

Implements IFlyable
Implements ISwimmable

Public Sub IFlyable_Fly()
End Sub

Public Function IFlyable_GetAltitude() As Long
End Function    

Public Sub ISwimmable_Swim()
End Sub

Public Function ISwimmable_GetDepth() As Long
End Function

这一切都编译得很好。但是如果我声明一个 IFlySwim 类型的对象,VBA 中的预测文本会给我:

尝试创建一个实现 IFlySwimmable 的类是行不通的。

鸭班:

Implements IFlySwim

Public Sub IFlySwim_IFlyable_Fly()
    Debug.Print "Flying with wings!"
End Sub

Public Function IFlySwim_IFlyable_GetAltitude() As Long
    IFlySwim_IFlyable_GetAltitude = 30
End Function

Public Sub IFlySwim_ISwimmable_Swim()
    Debug.Print "Swimming with feet!"
End Sub

Public Function IFlySwim_ISwimmable_GetDepth() As Long
    IFlySwim_ISwimmable_GetDepth = 20
End Function

按下编译按钮给了我错误: "编译错误:对象模块需要为接口'IFlySwim'实现'IFlyable_Fly'。

所以这让我相信Implement在另一个接口中使用一个接口是行不通的。或者至少,从 VBA 的角度来看,它没有意义。这是可以理解的,因为我实际上并没有在IFlySwim 中提供IFlyableISwimmable 的实现。我真正想做的是将IFlyableISwimmable 的实现推迟到实现它们的类。

那么现在,如果我的Duck 班级是:

Implements IFlyable
Implements ISwimmable

Public Sub IFlyable_Fly()
    Debug.Print "Flying with wings!"
End Sub

Public Function IFlyable_GetAltitude() As Long
    IFlyable_GetAltitude = 30
End Function

Public Sub ISwimmable_Swim()
    Debug.Print "Swimming with feet!"
End Sub

Public Function ISwimmable_GetDepth() As Long
    ISwimmable_GetDepth = 20
End Function

然后当我去使用它时,预测下拉菜单给了我:

我可以将Duck 转换为IFlyableISwimmable 以这样使用:

但是如果我想创建一个接受 Flyable/Swimmable 的 Function 或 Sub 怎么办?我是否必须创建一个名为 IFlySwim 的完全独立的接口,其中包含来自IFlyableISwimmable 的所有子/函数,然后修改我的Duck 类以仅从IFlySwim 实现?

【问题讨论】:

    标签: vba class interface


    【解决方案1】:

    不幸的是,这就是组合继承的工作原理。但是,您应该意识到您的 Duck 类将接口与函数实现的具体实现联系起来。您需要使用第二级间接

    Implements IFlyable
    Implements ISwimmable
    
    Private Sub IFlyable_Fly()
        Fly
    End Sub
    
    |Private Function IFlyable_GetAltitude() As Long
        IFlyable_GetAltitude=GetAltitude
    End Function
    
    Private Sub ISwimmable_Swim()
        Swim
    End Sub
    
    Private Function ISwimmable_GetDepth() As Long
        ISwimmable=GetDepth
    End Function
    
    Public Sub Fly()
        Debug.Print "Flying with wings!"
    End Sub
    
    Public Function GetAltitude() As Long
        GetAltitude = 30
    End Function
    
    Public Sub Swim()
        Debug.Print "Swimming with feet!"
    End Sub
    
    Public Function GetDepth() As Long
        GetDepth = 20
    End Function
    

    从中可以看出,GetAltitude 和 GetDepth 都可以引用 VerticalPosition 的属性

    Private Function IFlyable_GetAltitude() As Long
            IFlyable_GetAltitude=GetVerticalPosition
    End Function
    
    
    Private Function ISwimmable_GetDepth() As Long
        ISwimmable_GetDepth=- GetVerticalPosition
    End function
    

    这可能对您有帮助,也可能对您没有帮助。

    【讨论】:

    • 谢谢 - 但是我不明白为什么我需要另一个级别的间接。我的意思是,如果我也想允许GetVerticalPosition 方法,我会明白,但为什么我需要这样做:Private Sub ISwimmable_Swim()ISwimmable=SwimEnd SubPrivate Sub SwimDebug.Print "Swimming"End Sub
    • 它允许公开使用方法名称而无需其接口前缀。这对您可能很重要,也可能不重要。因此,对于您的 Iflyable 示例,下拉菜单将是 Fly、GetAltitude、GetDepth、Swim。
    • 哦,我明白了。好吧,只有当我将 Dim 对象作为类而不是接口时。我想我找到了一个很好的解决方案,虽然它有点长。我稍后会发布。
    【解决方案2】:

    接口方法/属性(即带有下划线前缀的方法/属性)不应公开。必须实现它们以履行派生类中接口的约定,但应将它们标记为私有。完成此操作后,您可以使用 FlyGetAltitude 之类的方法名称公开公共成员(见下文):

    Option Explicit
    
    Implements ISwimmable
    Implements IFlyable
    
    '********************************************************
    'Public Methods
    '********************************************************
    Public Function GetDepth() As Long
    
        GetDepth = 10
    
    End Function
    
    Public Sub Swim()
    
        Debug.Print "Swimming!"
    
    End Sub
    
    Public Function GetAltitude() As Long
    
        GetAltitude = 50
    
    End Function
    
    
    Public Sub Fly()
    
        Debug.Print "Flying with wings!"
    
    End Sub
    
    
    '********************************************************
    'Private Methods
    '********************************************************
    Private Function ISwimmable_GetDepth() As Long
    End Function
    
    Private Sub ISwimmable_Swim()
    End Sub
    
    
    Private Function IFlyable_GetAltitude() As Long
    End Function
    
    Private Sub IFlyable_Fly()
    End Sub
    

    你的测试代码变成如下:(见下文)

    Sub InterfaceTest()
    
        Dim ducky As New Duck
    
        ducky.Fly
        Debug.Print ducky.GetAltitude()
    
        ducky.Swim
        Debug.Print ducky.GetDepth()
    
    End Sub
    

    但是如果我想创建一个接受 Flyable/Swimmable 的 Function 或 Sub 怎么办?我是否必须创建一个名为 IFlySwim 的完全独立的接口,其中包含来自 IFlyable 和 ISwimmable 的所有子/功能,然后修改我的 Duck 类以仅从 IFlySwim 实现?

    简短的回答:是的。

    为什么?

    因为,VBA/VB6 不完全支持继承。按照您的要求,您将创建一个继承自ISwimmableIFlyable 的第三个类,然后在其他类中实现该类。

    在像 C# 这样的完全 OOP 语言中,您可以执行以下操作:(见下文)

    public interface IFlyable   {
    
        void Fly(); 
        int GetAltitude(); 
    
    } 
    
    
    public interface ISwimmable {
    
        void Swim();
        int GetDepth();
    
    } 
    
    //Base Class
    public abstract class BaseDuck: ISwimmable, IFlyable    {
    
        public BaseDuck(){}
    
        public void Fly()   {
    
            Console.WriteLine("Flying with wings!"); 
    
        } 
    
        public virtual int GetAltitude()    {
    
            return 50; 
    
        } 
    
        public void Swim()  {
    
            Console.WriteLine("Swimming!"); 
    
        } 
    
        public virtual int GetDepth()   {
    
            return 10; 
    
        } 
    
    
    }
    
    //Derived Class
    public class SeaDuck: BaseDuck  {
    
        public SeaDuck(){}
    
        public override int GetAltitude()   {
    
            return 50; 
    
        } 
    
        public override int GetDepth()  {
    
            return 100; 
    
        } 
    
        public void RideWaves() {
    
            Console.WriteLine("Riding waves!");
    
        }
    
    }
    
    //Derived Class
    public class MallardDuck: BaseDuck  {
    
        public MallardDuck(){}
    
        public override int GetAltitude()   {
    
            return 100; 
    
        } 
    
        public override int GetDepth()  {
    
            return 10; 
    
        } 
    
        public void HeadToLandForWinter()   {
    
            Console.WriteLine("Headed for land!");
    
        }
    
    }
    

    使用以下测试:(见下文)

    using System;
    
    public class Program
    {
        public static void Main()
        {
            SeaDuck seaDuck = new SeaDuck();
    
            Console.WriteLine("Sea Duck:");
            seaDuck.Fly();
            Console.WriteLine(seaDuck.GetAltitude().ToString()); 
    
            seaDuck.Swim();
            Console.WriteLine(seaDuck.GetDepth().ToString()); 
    
            seaDuck.RideWaves(); 
    
            Console.WriteLine("\n");
    
            Console.WriteLine("Mallard Duck:");
            MallardDuck mallardDuck = new MallardDuck();
            mallardDuck.Fly();
            Console.WriteLine(mallardDuck.GetAltitude().ToString()); 
    
            mallardDuck.Swim();
            Console.WriteLine(mallardDuck.GetDepth().ToString()); 
    
            mallardDuck.HeadToLandForWinter();
    
        }
    }
    

    生产:

    Sea Duck:
    Flying with wings!
    50
    Swimming!
    100
    Riding waves!
    
    
    Mallard Duck:
    Flying with wings!
    100
    Swimming!
    10
    Headed for land!
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-09
      • 1970-01-01
      • 2015-10-09
      • 2013-10-07
      相关资源
      最近更新 更多