【问题标题】:Interfaces and Headers接口和头文件
【发布时间】:2014-05-07 00:10:23
【问题描述】:

今天我遇到了 C# 接口的概念,我希望有一个简单的问题,看看我是否理解它们……它们与 C++ 头文件非常相似吗?我的意思是,从我得到的信息来看,你定义了一个类的主干而没有真正定义它的作用,这有点类似于标题,对吗?我阅读了整个 MSDN 定义,但它并没有真正让我 100% 清楚。我相信我有这个想法(编写并附加了一个非常基本的程序,看看我是否理解)但我至少在明天晚上之前完全理解它们的基础知识是非常重要的。

示例:

namespace InterfaceTest
{
    class Program
    {
        static void Main(string[] args)
        {
            KitchenStaff newKitchen = new KitchenStaff();
            newKitchen.getBakers();
            newKitchen.getBaristas();
            newKitchen.getCooks();
            Console.ReadLine();

            KitchenDuties newKitchen1 = new KitchenDuties();
            newKitchen1.getBakers();
            newKitchen1.getBaristas();
            newKitchen1.getCooks();
            Console.ReadLine();
        }
    }

    interface Bakers
    {
        void getBakers();
    }
    interface Cooks
    {
        void getCooks();
    }
    interface Baristas
    {
        void getBaristas();
    }

    class KitchenInfo
    {
        private string m_kitchen_name = "";
        private Int16 m_bakers = 0;
        private Int16 m_baristas = 0;
        private Int16 m_cooks = 0;

        public string Name
        {
            get
            {
                return m_kitchen_name.ToString();
            }
            set
            {
                m_kitchen_name = value;
            }
        }
        public string Bakers
        {
            get
            {
                return m_bakers.ToString();
            }
            set
            {
                m_bakers = Convert.ToInt16(value);
            }
        }
        public string Baristas
        {
            get
            {
                return m_baristas.ToString();
            }
            set
            {
                if (value != string.Empty)
                {
                    m_baristas = Convert.ToInt16(value);
                }
            }
        }
        public string Cooks
        {
            get
            {
                return m_cooks.ToString();
            }
            set
            {
                if (value != string.Empty)
                {
                    m_cooks = Convert.ToInt16(value);
                }
            }
        }
    }

    class KitchenStaff : KitchenInfo, Bakers, Cooks, Baristas
    {
        public KitchenStaff()
        {
            Console.WriteLine("What is this kitchens name?");
            Name = Console.ReadLine();

            Console.WriteLine("How many bakers?");
            Bakers = Console.ReadLine();

            Console.WriteLine("How many baristas?");
            Baristas = Console.ReadLine();

            Console.WriteLine("How many cooks?");
            Cooks = Console.ReadLine();
        }
        public void getBakers()
        {
            System.Console.WriteLine("In {0} there are {1} bakers.", Name, Bakers);
        }
        public void getBaristas()
        {
            System.Console.WriteLine("In {0} there are {1} baristas.", Name, Baristas);
        }
        public void getCooks()
        {
            System.Console.WriteLine("In {0} there are {1} cooks.", Name, Cooks);
        }
    }
    class KitchenDuties : KitchenInfo, Bakers, Cooks, Baristas
    {
        public KitchenDuties()
        {
            Console.WriteLine("What is this kitchens name?");
            Name = Console.ReadLine();

            Console.WriteLine("How many bakers?");
            Bakers = Console.ReadLine();

            Console.WriteLine("How many baristas?");
            Baristas = Console.ReadLine();

            Console.WriteLine("How many cooks?");
            Cooks = Console.ReadLine();
        }
        public void getBakers()
        {
            System.Console.WriteLine("In {0}, the {1} bakers make fattening cookies.", Name, Bakers);
        }
        public void getBaristas()
        {
            System.Console.WriteLine("In {0}, the {1} baristas serve hot coffee.", Name, Baristas);
        }
        public void getCooks()
        {
            System.Console.WriteLine("In {0}, the {1} cooks make tender steak.", Name, Cooks);
        }
    }
}

【问题讨论】:

  • C# 接口映射到 C++ 抽象类
  • 仅当抽象类是纯虚拟的。

标签: c# c++ inheritance interface


【解决方案1】:

从概念上讲,您似乎并不了解接口。

虽然 C# 中的接口具有特定含义,但在任何面向对象语言(包括 C++)中更普遍的是,您可以谈论类的“公共接口”。这本质上是另一个类可以看到的:它看不到私有成员,也看不到方法的内容,它只能看到其公共成员的签名

例如,如果我有一个班级:

public class MyClass
{
    private int _myPrivateInt;
    public int MyPublicInt;

    private void DoSomethingPrivate(int input)
    {
        //Some code goes here
    }

    public void DoSomethingPublic(int input)
    {
        //Some more code goes here
    }
}

所有对不同班级“可见”的内容将是:

int MyPublicInt;
void DoSomethingPublic(int input);

这是为了封装——一个类不应该关心另一个类的具体实现细节。 MyClass 公开声明其他类需要知道如何与之交互,并将其他所有内容保留给自己。

这就是接口实际上是什么的想法,而在 C# 中,接口几乎是一种无需公共方法即可指定该信息的方法。要了解原因,您需要了解一个相关概念,多态性。考虑这些类:

public class InMemoryCustomerDataStorage
{
    public void StoreCustomerInfo(CustomerInfo info)
    {
        //Actual implementation goes here
    }

    public CustomerInfo RetrieveCustomerInfo(int customerId)
    {
        //Actual implementation goes here
    }
}

public class DatabaseCustomerDataStorage
{
    public void StoreCustomerInfo(CustomerInfo info)
    {
        //Actual implementation goes here
    }

    public CustomerInfo RetrieveCustomerInfo(int customerId)
    {
        //Actual implementation goes here
    }
}

public class FileCustomerDataStorage
{
    public void StoreCustomerInfo(CustomerInfo info)
    {
        //Actual implementation goes here
    }

    public CustomerInfo RetrieveCustomerInfo(int customerId)
    {
        //Actual implementation goes here
    }
}

这三者的目的相同,但方式不同。它们都允许您存储客户信息,并通过 id 检索它。他们还可能有我没有写出的其他私有成员,例如,如果文件不存在,文件可能有一个创建文件的方法,等等。当然,他们都有实际的实现而不是那些 cmets , 我没有把它们全部写出来,因为这只是一个例子。

那么界面如何在这里派上用场?重点是您的程序的某些部分可能想要存储和检索客户信息,但并不关心它是如何完成的。事实上,一般来说,他们不应该具体说明如何存储它,除非他们直接需要关心。如果随着程序的增长,您需要更改使用的存储类型怎么办?你必须找到你写的每个地方InMemoryCustomerDataStorage 并用DatabaseCustomerDataStorage 替换它。或者,如果您想在大部分时间使用数据库,但在测试代码时,您想在内存存储中使用它以便快速运行,该怎么办?您甚至可以编写一个需要进行数据存储但本身不包含数据存储类的库。解决方案是使用接口。你会写:

public interface ICustomerDataStorage
{
    void StoreCustomerInfo(CustomerInfo info);
    CustomerInfo RetrieveCustomerInfo(int customerId);
}

那么在需要存储一些客户数据的类中可能是这样的:

public class NewCustomerProcessor
{
    private ICustomerDataStorage _storage;

    public NewCustomerProcessor(ICustomerDataStorage storage)
    {
        _storage = storage;
    }

    public void Process(string name, string address, string email, int age)
    {
        CustomerInfo info = new CustomerInfo(name, address, email, age);
        if(Validate(info))
            _storage.StoreCustomerInfo(info);
    }

    private bool Validate(CustomerInfo info)
    {
         //Some validation logic
    }
}

现在这个类功能齐全,它在任何时候都不必担心使用 ICustomerDataStorage 的哪个具体实现。它可以存储在内存中,文件中,数据库中,它不在乎。实现 ICustomerDataStorage 的类可以在完全不同的程序集和项目中,我可以将我的项目放在 github 上,任何下载它以在自己的项目中使用的人都可以编写自己的 ICustomerDataStorage 实现。

【讨论】:

  • +1 这是对接口应用的优秀介绍。
【解决方案2】:

不,它与头文件不同。 C++ 有头文件和 cpp 文件,因此可以拆分声明和定义。 C# 结合了这些,因此您没有单独的声明。

C# Interface 在 C++ 中没有直接等价物。最接近的是 C++ 中的抽象虚拟类。

【讨论】:

    【解决方案3】:

    不,它们与 C/C++ 中的标头不同。 它是 C# 和 Java 等“现代”语言中使用的概念。它允许每个类继承一组特征。

    它是纯粹的抽象类,除了声明您要使其可用于继承的方法之外不包含任何代码。

    最常见的例子是 C# 中的IEnumerable 接口,它允许您在新定义的类对象上使用foreach 语句。

    【讨论】:

    • 不那么明显,但 IDisposable 也非常常见。您还可以在界面中指定自动属性。从技术上讲,它们仍然是方法,但它们看起来不像。
    猜你喜欢
    • 1970-01-01
    • 2017-11-20
    • 1970-01-01
    • 2011-11-22
    • 1970-01-01
    • 2020-01-04
    • 2019-06-13
    • 2013-09-04
    • 1970-01-01
    相关资源
    最近更新 更多