- UID
- 479441
- 最后登录
- 1970-1-1
- 阅读权限
- 205
- 精华
- 主题
- 回帖
- 0
- 积分
- 1289
- PB币
-
- 威望
-
- 贡献
-
- 技术
-
- 活跃
-
|
看到接口,我就情不自禁地想起了大二的时候,辅导员,也是我们的Java老师,在讲台上大讲特讲接口的广泛用途。是的,接口这个东西无时无刻不让我想起Java。
说实话我不喜欢Java,这东西总有种让我不能把一切尽在掌握的感觉。Java的“高级”特性让我们看不到内存里的东西,这在调试时是非常不方便的(对我来说)。我喜欢在调试时看着我要监视的内存块,然后内容一点点变化,成就感油然而生。当然,出现错误也能第一时间明白是肿么回事。
万幸(或者说是不幸?),C++也引入了接口这种特性。在让子类有更多可定制性的同时,也将C++变得更加多元化,复杂化。
C++/CX中的接口也是一个ref类,一个接口类(或接口结构)自身可继承(或需要)多个接口类、可重载其成员函数,也可具有类型参数。
新的接口类具有以下特性:
1. 接口类(或结构)必须在命名空间内声明且可具有公共或私有可访问性。仅将公共接口发送到元数据。
2. 接口的成员可以包括属性、方法和事件。
3. 所有接口成员既是隐式公开的又是virtual的。
4. 不允许字段和静态成员。
5. 用作属性、方法参数或返回值的类型只能是 Windows 运行时类型;这包括基本类型和枚举类类型。
下面的例子示范了如何声明和实现接口:
-声明与实现-
- using namespace Platform;
- namespace InterfacesTest
- {
- public enum class PlayState {Playing, Paused, Stopped, Forward, Reverse};
- public ref struct MediaPlayerEventArgs sealed
- {
- property PlayState oldState;
复制代码
一个接口可从一个或多个接口继承。但与 ref 类或 ref 结构不同,接口不声明继承的接口成员。如果接口 B 从接口 A 继承,而 ref 类 C 从 B 继承,则 C 必须同时实现 A 和 B。如下:
- public interface struct A { void DoSomething(); };
- public interface struct B : A { void DoSomethingMore();};
- public ref struct C sealed : B // can not be derived
- {
- virtual void DoSomething(){}
- virtual void DoSomethingMore(){}
- };
复制代码
我们还可以使用普通虚拟属性(virtual property)实现接口属性,并可以在实现类中提供自定义 getter 和 setter。
- // 接上面MyMediaPlayer类,实现CurrentTitle属性
- virtual property Platform::String^ CurrentTitle
- {
- Platform::String^ get() {return "Now playing: " + _title;}
- void set(Platform::String^ t) {_title = t; }
- }
复制代码
而如果接口声明仅有 getter 或仅有 setter 的属性,则实现类应显式提供 getter 或 setter。
- public interface class IMediaPlayer
- {
- //...
- property Platform::String^ CurrentTitle
- {
- Platform::String^ get();
复制代码
-泛型接口-
泛型这个概念对于使用.Net编程的人来说,应该不陌生。它为使用c#语言编写面向对象程序增加了极大的效力和灵活性。通过使用泛型类型参数 T,在编写其他客户端代码时能够使用的单个类,而不致引入运行时强制转换或装箱操作的成本或风险。
在C++/CX中,我们使用generic关键字来表示参数化类型(parameteric type)。不支持在 C++/CX 中创建公共用户定义的泛型接口。但可以创建私有泛型接口。
在下面的例子中,我们可以知道如何创建泛型接口,并在私有ref类中实现它,然后在公共ref类中将该类当作私有成员。
- // 接上面,在InterfacesTest namespace中
- public ref class MediaFile sealed {};
- // generic interface
- generic <typename T>
- private interface class IFileCollection
- {
- property Windows::Foundation::Collections::IVector<T>^ Files;
- Platform::String^ GetFileInfoAsString(T file);
- };
- // private ref class that implements the generic interface
- private ref class MediaFileCollection : IFileCollection<MediaFile^>
- {
- public:
- virtual property Windows::Foundation::Collections::IVector<MediaFile^>^ Files;
- virtual Platform::String^ GetFileInfoAsString(MediaFile^ file){return "";}
- };
- public interface class ILibraryClient
- {
- bool FindTitle(Platform::String^ title);
- //...
- };
- // public ref class who has the implemention class as a private member
- public ref class MediaPlayer sealed : public IMediaPlayer, public ILibraryClient
- {
- public:
- //IMediaPlayer
- virtual event OnStateChanged^ StateChanged;
- virtual property Platform::String^ CurrentTitle;
- virtual property PlayState CurrentState;
- virtual void Play()
- {
- auto args = ref new MediaPlayerEventArgs();
复制代码
可以看到,在MediaFileCollection类中,传入了MediaFile^当作参数类型。任何一个实现IFileCollection的ref类都可以传入自己独特的ref类当作参数类型。泛型的优点展露无遗。
泛型接口的注意事项(万金油,来自MSDN):
1. 泛型接口必须遵循控制可访问性、成员、需要关系、基类等内容的标准接口规则。
2. 泛型接口可以采用前面带有 typename 或 class 的一个或多个泛型类型参数。不支持非类型参数。
3. 类型参数可以是任何 Windows 运行时类型。即,类型参数可以是引用类型、值类型、接口类、委托、基本类型或公共枚举类。
4. 封闭式泛型接口 是从泛型接口继承的接口,并对所有类型形参指定具体的类型实参。它可以在可使用非泛型私有接口的任意位置使用。
5. 开放式泛型接口 是具有一个或多个尚未为其提供具体类型的类型参数的接口。它可以在可使用类型的任意位置使用,包括用作另一个泛型接口的类型参数。
6. 可以只参数化整个接口,而不是单个方法。
7. 不能约束类型参数。
8. 封闭式泛型接口具有隐式生成的 UUID。用户不能指定 UUID。
9. 在接口中,对当前接口的任何引用(在方法参数、返回值或属性中)都假定引用当前实例化。例如,IMyIntf 表示 IMyIntf<T>。
10. 当方法参数的类型是类型参数时,该参数或变量的声明将使用类型参数的名称,而不带任何指针、本机引用或句柄声明符。换言之,绝不会写入“T^”。
11. 模板化的 ref 类必须是私有的。它们可以实现泛型接口,并且可以将模板形参 T 传递给泛型实参 T。模板化 ref 类的每个实例化本身都是一个 ref 类。
以上是关于接口的文章。下篇文章让我们讲讲C++/CX相对C++来说,有哪些习惯了的东西从我们的视野中消失了。
我的个人博客:http://www.cy198706.com 转载的话,请告知。
|
|