9.9.4 定义接口类(1)
我们使用关键字interface class或interface struct定义接口类。无论是使用interface class还是interface struct来定义接口,接口的所有成员默认都是公有的,我们不能将它们指定为其他类型。接口的成员可以是函数-- 包括运算符函数、属性、静态字段和事件,所有这些都将在本章稍后学习。接口还可以指定静态构造函数,可以包含任何种类的嵌套类定义。尽管这些潜在成员都具有多样性,大多数接口还是相对简单的。注意,我们可以从一个接口派生出另一个接口,方法基本上与派生引用类时使用的方法相同。例如:
- interface class IController : ITelevison, IRecorder
- {
- // Members of IController...
- };
IController接口包含自己的成员,还继承了ITelevision和IRecorder接口的成员。实现IController接口的类必须定义来自IController、ITelevision和IRecorder的成员函数。
我们可以使用接口代替Ex9_14中的基类Container。下面是该接口的定义:
- // IContainer.h for Ex9_15
- #pragma once
-
- interface class IContainer
- {
- double Volume(); // Function for calculating a volume
- void ShowVolume(); // Function to display a volume
- };
按照约定,C++(www.cppentry.com)/CLI中的接口名以I打头,因此这里的接口名是IContainer。该接口有两个成员:Volume()函数和ShowVolume()函数。这两个函数都是公有的,因为接口的成员始终都是公有的。两个函数实际上是抽象函数,因为接口永远不包括函数定义。当然,我们可以给这两个函数添加abstract关键字,但这样做是不必要的。接口定义中的实例函数可以被指定为virtual和abstract,但这也不是必需的,因为它们无论如何都是虚函数和抽象函数。
任何实现IContainer接口的类如果不是抽象类的话,就必须实现这两个函数。下面看看Box类:
- // Box.h for Ex9_15
- #pragma once
-
- #include "IContainer.h" // For interface definition
-
- using namespace System;
-
- ref class Box : IContainer
- {
- public:
- // Function to show the volume of an object
- virtual void ShowVolume()
- {
- Console::WriteLine(L"CBox usable volume is {0}", Volume());
- }
-
- // Function to calculate the volume of a Box object
- virtual double Volume()
- { return m_Length*m_Width*m_Height; }
-
- // Constructor
- Box() : m_Length(1.0), m_Width(1.0), m_Height(1.0){}
-
- // Constructor
- Box(double lv, double wv, double hv)
- : m_Length(lv),
m_Width(wv), m_Height(hv){} -
- protected:
- double m_Length;
- double m_Width;
- double m_Height;
- };
接口的名称写在类定义中第一行的冒号后面,就好像接口是个基类一样。当然,Box类也可以拥有基类,那样接口的名称应当跟在基类的名称之后,两者之间以逗号分开。一个类可以实现多个接口,这种情况下接口的名称之间也应当以逗号分开。
Box类必须实现IContainer接口类的两个函数成员,不然它就是一个抽象类,需要用abstract关键字进行声明。Box类中这两个函数的定义没有附加override关键字,因为我们不是在重写现有的函数,而是在初次实现Volume()和ShowVolume()函数。
GlassBox类是从Box类派生的,因此将继承IContainer的实现。GlassBox类的定义完全不需要任何修改,就能适应IContainer接口类的引入。
在多态性方面,IContainer接口类扮演着与基类相同的角色。我们可以使用IContainer类型的句柄,存储任何实现了该接口的类类型的对象地址。因此,IContainer类型的句柄可以用来引用Box类型或GlassBox类型的对象,并在调用接口类的成员函数时获得多态的行为。让我们来试一下。