博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(原創) 如何讓泛型支援多個interface? (.NET) (C/C++) (C#) (template) (C++/CLI)
阅读量:6371 次
发布时间:2019-06-23

本文共 16921 字,大约阅读时间需要 56 分钟。

Abstract

在中,我們看到了.NET的Generics的multiple constraints是AND的關係,而非OR的關係,若要讓泛型支援OR的關係該如何做呢?
Introduction
我希望有一個Generic Handler,能同時支援Interface1和Interface2,UML表示如下
ISO C++

 1
ExpandedBlockStart.gif
ContractedBlock.gif
/**/
/* 
 2InBlock.gif(C) OOMusou 2007 http://oomusou.cnblogs.com
 3InBlock.gif
 4InBlock.gifFilename    : Template_SupportMultiInterface.cpp
 5InBlock.gifCompiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
 6InBlock.gifDescription : Demo how to use template support multiple interface
 7InBlock.gifRelease     : 06/16/2007 1.0
 8ExpandedBlockEnd.gif*/
 9
None.gif#include 
<
iostream
>
10
None.gif
11
None.gif
using
 
namespace
 std;
12
None.gif
13
ExpandedBlockStart.gifContractedBlock.gif
class
 Interface1 
dot.gif
{
14InBlock.gifpublic:
15InBlock.gif  virtual void func1() = 0;
16InBlock.gif  virtual void func2() = 0;
17ExpandedBlockEnd.gif}
;
18
None.gif
19
ExpandedBlockStart.gifContractedBlock.gif
class
 Interface2 
dot.gif
{
20InBlock.gifpublic:
21InBlock.gif  virtual void func1() = 0;
22InBlock.gif  virtual void func3() = 0;
23ExpandedBlockEnd.gif}
;
24
None.gif
25
ExpandedBlockStart.gifContractedBlock.gif
class
 Class1 : 
public
 Interface1 
dot.gif
{
26InBlock.gifpublic:
27ExpandedSubBlockStart.gifContractedSubBlock.gif  void func1() dot.gif{
28InBlock.gif    cout << "Class1's func1" << endl;
29ExpandedSubBlockEnd.gif  }
30ExpandedSubBlockStart.gifContractedSubBlock.gif  void func2() dot.gif{
31InBlock.gif    cout << "Class1's func2" << endl;
32ExpandedSubBlockEnd.gif  }
33ExpandedBlockEnd.gif}
;
34
None.gif
35
ExpandedBlockStart.gifContractedBlock.gif
class
 Class2 : 
public
 Interface2 
dot.gif
{
36InBlock.gifpublic:
37ExpandedSubBlockStart.gifContractedSubBlock.gif  void func1() dot.gif{
38InBlock.gif    cout << "Class2's func1" << endl;
39ExpandedSubBlockEnd.gif  }
40ExpandedSubBlockStart.gifContractedSubBlock.gif  void func3() dot.gif{
41InBlock.gif    cout << "Class2's func3" << endl;
42ExpandedSubBlockEnd.gif  }
43ExpandedBlockEnd.gif}
;
44
None.gif
45
ExpandedBlockStart.gifContractedBlock.gif
class
 IGeneric 
dot.gif
{
46InBlock.gifpublic:
47InBlock.gif  virtual void func1() = 0;
48InBlock.gif  virtual void func2() = 0;
49InBlock.gif  virtual void func3() = 0;
50ExpandedBlockEnd.gif}
;
51
None.gif
52
None.giftemplate
<
typename T
>
53
ExpandedBlockStart.gifContractedBlock.gif
class
 GenericHandler : 
public
 IGeneric 
dot.gif
{
54InBlock.gifprivate:
55InBlock.gif  T* _aClass;
56InBlock.gif
57InBlock.gifpublic:
58ExpandedSubBlockStart.gifContractedSubBlock.gif  GenericHandler(T* aClass) dot.gif{
59InBlock.gif    _aClass = aClass;
60ExpandedSubBlockEnd.gif  }
61InBlock.gif
62ExpandedSubBlockStart.gifContractedSubBlock.gif  void func1() dot.gif{
63InBlock.gif    _aClass->func1();
64ExpandedSubBlockEnd.gif  }
65InBlock.gif  
66ExpandedSubBlockStart.gifContractedSubBlock.gif  void func2() dot.gif{
67InBlock.gif    dynamic_cast<Interface1*>(_aClass)->func2();
68ExpandedSubBlockEnd.gif  }
69InBlock.gif  
70ExpandedSubBlockStart.gifContractedSubBlock.gif  void func3() dot.gif{
71InBlock.gif    dynamic_cast<Interface2*>(_aClass)->func3();
72ExpandedSubBlockEnd.gif  }
73ExpandedBlockEnd.gif}
;
74
None.gif
75
None.gif
76
ExpandedBlockStart.gifContractedBlock.gif
int
 main() 
dot.gif
{
77InBlock.gif  Interface1* obj1 = new Class1;
78InBlock.gif  Interface2* obj2 = new Class2;
79InBlock.gif  
80InBlock.gif  IGeneric* foo = new GenericHandler<Interface1>(obj1);
81InBlock.gif  foo->func1();
82InBlock.gif  foo->func2();
83InBlock.gif  
84InBlock.gif  foo = new GenericHandler<Interface2>(obj2);
85InBlock.gif  foo->func1();
86InBlock.gif  foo->func3();
87ExpandedBlockEnd.gif}

執行結果

None.gif
Class1's func1
None.gifClass1's func2
None.gifClass2's func1
None.gifClass2's func3

ISO C++的template本來就類似macro,所以code並不讓人訝異,唯一是67行和71行的

None.gif
dynamic_cast
<
Interface1
*>
(_aClass)
->
func2();
None.gif
dynamic_cast
<
Interface2
*>
(_aClass)
->
func3();

是不得已而為之,因為func2本來就是Interface1獨有,而func3也是Interface2所獨有,所以得用casting。
C#
C#的泛型是用Generics,比較類似polymorphism的加強版,最大的特色就是要靠constraints,也因為如此,所以整個架構做了小小的調整,如同上一篇的技巧,將func1往上提到InterfaceBase,讓constraint為InterfaceBase。

 1
ExpandedBlockStart.gif
ContractedBlock.gif
/**/
/* 
 2InBlock.gif(C) OOMusou 2007 http://oomusou.cnblogs.com
 3InBlock.gif
 4InBlock.gifFilename    : Generics_SupportMultiInterface.cs
 5InBlock.gifCompiler    : Visual Studio 2005 / C# 2.0
 6InBlock.gifDescription : Demo how to support multiple interface in Generics
 7InBlock.gifRelease     : 06/16/2007 1.0
 8ExpandedBlockEnd.gif*/
 9
None.gif
using
 System;
10
None.gif
11
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 InterfaceBase 
dot.gif
{
12InBlock.gif  void func1();
13ExpandedBlockEnd.gif}
14
None.gif
15
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 Interface1 : InterfaceBase 
dot.gif
{
16InBlock.gif  void func2();
17ExpandedBlockEnd.gif}
18
None.gif
19
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 Interface2 : InterfaceBase 
dot.gif
{
20InBlock.gif  void func3();
21ExpandedBlockEnd.gif}
22
None.gif
23
ExpandedBlockStart.gifContractedBlock.gif
public
 
class
 Class1 : Interface1 
dot.gif
{
24ExpandedSubBlockStart.gifContractedSubBlock.gif  public void func1() dot.gif{
25InBlock.gif    Console.WriteLine("Class1's func1");
26ExpandedSubBlockEnd.gif  }
27InBlock.gif  
28ExpandedSubBlockStart.gifContractedSubBlock.gif  public void func2() dot.gif{
29InBlock.gif    Console.WriteLine("Class1's func2");
30ExpandedSubBlockEnd.gif  }
31ExpandedBlockEnd.gif}
32
None.gif
33
ExpandedBlockStart.gifContractedBlock.gif
public
 
class
 Class2 : Interface2 
dot.gif
{
34ExpandedSubBlockStart.gifContractedSubBlock.gif  public void func1() dot.gif{
35InBlock.gif    Console.WriteLine("Class2's func1");
36ExpandedSubBlockEnd.gif  }
37InBlock.gif
38ExpandedSubBlockStart.gifContractedSubBlock.gif  public void func3() dot.gif{
39InBlock.gif    Console.WriteLine("Class1's func3");
40ExpandedSubBlockEnd.gif  }
41ExpandedBlockEnd.gif}
42
None.gif
43
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 IGeneric 
dot.gif
{
44InBlock.gif  void func1();
45InBlock.gif  void func2();
46InBlock.gif  void func3();
47ExpandedBlockEnd.gif}
48
None.gif
49
ExpandedBlockStart.gifContractedBlock.gif
public
 
class
 GenericHandler
<
T
>
 : IGeneric where T : InterfaceBase 
dot.gif
{
50InBlock.gif  private T _aClass;
51InBlock.gif
52ExpandedSubBlockStart.gifContractedSubBlock.gif  public GenericHandler(T aClass) dot.gif{
53InBlock.gif    _aClass = aClass;
54ExpandedSubBlockEnd.gif  }
55InBlock.gif
56ExpandedSubBlockStart.gifContractedSubBlock.gif  public void func1() dot.gif{
57InBlock.gif    _aClass.func1();
58ExpandedSubBlockEnd.gif  }
59InBlock.gif  
60ExpandedSubBlockStart.gifContractedSubBlock.gif  public void func2() dot.gif{
61InBlock.gif    ((Interface1)_aClass).func2();
62ExpandedSubBlockEnd.gif  }
63InBlock.gif  
64ExpandedSubBlockStart.gifContractedSubBlock.gif  public void func3() dot.gif{
65InBlock.gif    ((Interface2)_aClass).func3();
66ExpandedSubBlockEnd.gif  }
67ExpandedBlockEnd.gif}
68
None.gif
69
ExpandedBlockStart.gifContractedBlock.gif
public
 
class
 main 
dot.gif
{
70ExpandedSubBlockStart.gifContractedSubBlock.gif  public static void Main() dot.gif{
71InBlock.gif    Interface1 obj1 = new Class1();
72InBlock.gif    Interface2 obj2 = new Class2();
73InBlock.gif    
74InBlock.gif    IGeneric foo = new GenericHandler<Interface1>(obj1);
75InBlock.gif    foo.func1();
76InBlock.gif    foo.func2();
77InBlock.gif
78InBlock.gif    foo = new GenericHandler<Interface2>(obj2);
79InBlock.gif    foo.func1();
80InBlock.gif    foo.func3();
81ExpandedSubBlockEnd.gif  }
82ExpandedBlockEnd.gif}

執行結果

None.gif
Class1's func1
None.gifClass1's func2
None.gifClass2's func1
None.gifClass2's func3

如同ISO C++,61行,65行還是得casting。

None.gif
((Interface1)_aClass).func2();
None.gif
((Interface2)_aClass).func3();

C++/CLI
這在C++/CLI就有趣了,因為C++/CLI提供兩種泛型,一種是ISO C++的template,一種是.NET的generics。
使用template

 1
ExpandedBlockStart.gif
ContractedBlock.gif
/**/
/*
 
 2
InBlock.gif(C) OOMusou 2006 
http://oomusou.cnblogs.com
 3
InBlock.gif
 4
InBlock.gifFilename    : Template_SupportMutipleInterface.cpp
 5
InBlock.gifCompiler    : Visual C++ 8.0 / C++/CLI
 6
InBlock.gifDescription : Demo how to support multiple interface in Generics
 7
InBlock.gifRelease     : 06/16/2007 1.0
 8
ExpandedBlockEnd.gif
*/
 9
None.gif#include 
"
stdafx.h
"
10
None.gif
11
None.gif
using
 
namespace
 System;
12
None.gif
13
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 Interface1 
dot.gif
{
14InBlock.gif  void func1();
15InBlock.gif  void func2();
16ExpandedBlockEnd.gif}
;
17
None.gif
18
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 Interface2 
dot.gif
{
19InBlock.gif  void func1();
20InBlock.gif  void func3();
21ExpandedBlockEnd.gif}
;
22
None.gif
23
ExpandedBlockStart.gifContractedBlock.gif
public
 
ref
 
class
 Class1 : 
public
 Interface1 
dot.gif
{
24InBlock.gifpublic:
25ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func1() dot.gif{
26InBlock.gif    Console::WriteLine("Class1's func1");
27ExpandedSubBlockEnd.gif  }
28InBlock.gif  
29ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func2() dot.gif{
30InBlock.gif    Console::WriteLine("Class1's func2");
31ExpandedSubBlockEnd.gif  }
32ExpandedBlockEnd.gif}
;
33
None.gif
34
ExpandedBlockStart.gifContractedBlock.gif
public
 
ref
 
class
 Class2 : 
public
 Interface2 
dot.gif
{
35InBlock.gifpublic:
36ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func1() dot.gif{
37InBlock.gif    Console::WriteLine("Class2's func1");
38ExpandedSubBlockEnd.gif  }
39InBlock.gif  
40ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func3() dot.gif{
41InBlock.gif    Console::WriteLine("Class2's func3");
42ExpandedSubBlockEnd.gif  }
43ExpandedBlockEnd.gif}
;
44
None.gif
45
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 IGeneric 
dot.gif
{
46InBlock.gif  void func1();
47InBlock.gif  void func2();
48InBlock.gif  void func3();
49ExpandedBlockEnd.gif}
;
50
None.gif
51
None.giftemplate
<
typename T
>
52
ExpandedBlockStart.gifContractedBlock.gif
public
 
ref
 
class
 GenericHandler : IGeneric 
dot.gif
{
53InBlock.gifprivate:
54InBlock.gif  T^ _aClass;
55InBlock.gif
56InBlock.gifpublic:
57ExpandedSubBlockStart.gifContractedSubBlock.gif  GenericHandler(T^ aClass) dot.gif{
58InBlock.gif    _aClass = aClass;
59ExpandedSubBlockEnd.gif  }
60InBlock.gif
61ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func1() dot.gif{
62InBlock.gif    _aClass->func1();
63ExpandedSubBlockEnd.gif  }
64InBlock.gif  
65ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func2() dot.gif{
66InBlock.gif    safe_cast<Interface1^>(_aClass)->func2();
67ExpandedSubBlockEnd.gif  }
68InBlock.gif  
69ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func3() dot.gif{
70InBlock.gif    safe_cast<Interface2^>(_aClass)->func3();
71ExpandedSubBlockEnd.gif  }
72ExpandedBlockEnd.gif}
;
73
None.gif
74
ExpandedBlockStart.gifContractedBlock.gif
int
 main() 
dot.gif
{
75InBlock.gif  Interface1^ obj1 = gcnew Class1;
76InBlock.gif  Interface2^ obj2 = gcnew Class2;
77InBlock.gif  
78InBlock.gif  IGeneric^ foo = gcnew GenericHandler<Interface1>(obj1);
79InBlock.gif  foo->func1();
80InBlock.gif  foo->func2();
81InBlock.gif  
82InBlock.gif  foo = gcnew GenericHandler<Interface2>(obj2);
83InBlock.gif  foo->func1();
84InBlock.gif  foo->func3();
85ExpandedBlockEnd.gif}

執行結果

None.gif
Class1's func1
None.gifClass1's func2
None.gifClass2's func1
None.gifClass2's func3

使用generics

 1
ExpandedBlockStart.gif
ContractedBlock.gif
/**/
/* 
 2InBlock.gif(C) OOMusou 2006 http://oomusou.cnblogs.com
 3InBlock.gif
 4InBlock.gifFilename    : Generic_SupportMutipleInterface.cpp
 5InBlock.gifCompiler    : Visual C++ 8.0 / C++/CLI
 6InBlock.gifDescription : Demo how to support multiple interface in Generics
 7InBlock.gifRelease     : 06/16/2007 1.0
 8ExpandedBlockEnd.gif*/
 9
None.gif#include 
"
stdafx.h
"
10
None.gif
11
None.gif
using
 
namespace
 System;
12
None.gif
13
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 InterfaceBase 
dot.gif
{
14InBlock.gif  void func1();
15ExpandedBlockEnd.gif}
;
16
None.gif
17
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 Interface1 : InterfaceBase 
dot.gif
{
18InBlock.gif  void func2();
19ExpandedBlockEnd.gif}
;
20
None.gif
21
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 Interface2 : InterfaceBase 
dot.gif
{
22InBlock.gif  void func3();
23ExpandedBlockEnd.gif}
;
24
None.gif
25
ExpandedBlockStart.gifContractedBlock.gif
public
 
ref
 
class
 Class1 : 
public
 Interface1 
dot.gif
{
26InBlock.gifpublic:
27ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func1() dot.gif{
28InBlock.gif    Console::WriteLine("Class1's func1");
29ExpandedSubBlockEnd.gif  }
30InBlock.gif  
31ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func2() dot.gif{
32InBlock.gif    Console::WriteLine("Class1's func2");
33ExpandedSubBlockEnd.gif  }
34ExpandedBlockEnd.gif}
;
35
None.gif
36
ExpandedBlockStart.gifContractedBlock.gif
public
 
ref
 
class
 Class2 : 
public
 Interface2 
dot.gif
{
37InBlock.gifpublic:
38ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func1() dot.gif{
39InBlock.gif    Console::WriteLine("Class2's func1");
40ExpandedSubBlockEnd.gif  }
41InBlock.gif  
42ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func3() dot.gif{
43InBlock.gif    Console::WriteLine("Class2's func3");
44ExpandedSubBlockEnd.gif  }
45ExpandedBlockEnd.gif}
;
46
None.gif
47
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 IGeneric 
dot.gif
{
48InBlock.gif  void func1();
49InBlock.gif  void func2();
50InBlock.gif  void func3();
51ExpandedBlockEnd.gif}
;
52
None.gif
53
None.gifgeneric
<
typename T
>
 
54
None.gif  where T : InterfaceBase
55
ExpandedBlockStart.gifContractedBlock.gif
public
 
ref
 
class
 GenericHandler : IGeneric 
dot.gif
{
56InBlock.gifprivate:
57InBlock.gif  T _aClass;
58InBlock.gif
59InBlock.gifpublic:
60ExpandedSubBlockStart.gifContractedSubBlock.gif  GenericHandler(T aClass) dot.gif{
61InBlock.gif    _aClass = aClass;
62ExpandedSubBlockEnd.gif  }
63InBlock.gif
64ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func1() dot.gif{
65InBlock.gif    _aClass->func1();
66ExpandedSubBlockEnd.gif  }
67InBlock.gif  
68ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func2() dot.gif{
69InBlock.gif    safe_cast<Interface1^>(_aClass)->func2();
70ExpandedSubBlockEnd.gif  }
71InBlock.gif  
72ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func3() dot.gif{
73InBlock.gif    safe_cast<Interface2^>(_aClass)->func3();
74ExpandedSubBlockEnd.gif  }
75ExpandedBlockEnd.gif}
;
76
None.gif
77
ExpandedBlockStart.gifContractedBlock.gif
int
 main() 
dot.gif
{
78InBlock.gif  Interface1^ obj1 = gcnew Class1;
79InBlock.gif  Interface2^ obj2 = gcnew Class2;
80InBlock.gif  
81InBlock.gif  IGeneric^ foo = gcnew GenericHandler<Interface1^>(obj1);
82InBlock.gif  foo->func1();
83InBlock.gif  foo->func2();
84InBlock.gif  
85InBlock.gif  foo = gcnew GenericHandler<Interface2^>(obj2);
86InBlock.gif  foo->func1();
87InBlock.gif  foo->func3();
88ExpandedBlockEnd.gif}

執行結果

None.gif
Class1's func1
None.gifClass1's func2
None.gifClass2's func1
None.gifClass2's func3

以上做法雖然可行,不過並不滿意,GenericHandler雖然同時支援了func1()、func2()、func3(),但func2()只有在泛型傳入為Interface1時使用才不會出現run-time error,若在傳入Interface2時去invoke了func2(),compiler並不會發現錯誤,要到run-time才發現錯誤。理想上,由於func1()對於Interface1或Interface2都支援,所以無論泛型傳入Interface1或Interface2,Interllisense皆該顯示func1(),但由於func2()只配合Interface1,func3()只配合Interface2,所以foo理想上應該透過一個casting後,才能顯示func2()或func3(),這樣可以避免client誤用而當機。

ISO C++

 1
ExpandedBlockStart.gif
ContractedBlock.gif
/**/
/* 
 2InBlock.gif(C) OOMusou 2007 http://oomusou.cnblogs.com
 3InBlock.gif
 4InBlock.gifFilename    : Template_SupportMultiInterface2.cpp
 5InBlock.gifCompiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
 6InBlock.gifDescription : Demo how to use template support multiple interface
 7InBlock.gifRelease     : 06/18/2007 1.0
 8ExpandedBlockEnd.gif*/
 9
None.gif#include 
<
iostream
>
10
None.gif
11
None.gif
using
 
namespace
 std;
12
None.gif
13
ExpandedBlockStart.gifContractedBlock.gif
class
 Interface1 
dot.gif
{
14InBlock.gifpublic:
15InBlock.gif  virtual void func1() = 0;
16InBlock.gif  virtual void func2() = 0;
17ExpandedBlockEnd.gif}
;
18
None.gif
19
ExpandedBlockStart.gifContractedBlock.gif
class
 Interface2 
dot.gif
{
20InBlock.gifpublic:
21InBlock.gif  virtual void func1() = 0;
22InBlock.gif  virtual void func3() = 0;
23ExpandedBlockEnd.gif}
;
24
None.gif
25
ExpandedBlockStart.gifContractedBlock.gif
class
 Class1 : 
public
 Interface1 
dot.gif
{
26InBlock.gifpublic:
27ExpandedSubBlockStart.gifContractedSubBlock.gif  void func1() dot.gif{
28InBlock.gif    cout << "Class1's func1" << endl;
29ExpandedSubBlockEnd.gif  }
30ExpandedSubBlockStart.gifContractedSubBlock.gif  void func2() dot.gif{
31InBlock.gif    cout << "Class1's func2" << endl;
32ExpandedSubBlockEnd.gif  }
33ExpandedBlockEnd.gif}
;
34
None.gif
35
ExpandedBlockStart.gifContractedBlock.gif
class
 Class2 : 
public
 Interface2 
dot.gif
{
36InBlock.gifpublic:
37ExpandedSubBlockStart.gifContractedSubBlock.gif  void func1() dot.gif{
38InBlock.gif    cout << "Class2's func1" << endl;
39ExpandedSubBlockEnd.gif  }
40ExpandedSubBlockStart.gifContractedSubBlock.gif  void func3() dot.gif{
41InBlock.gif    cout << "Class2's func3" << endl;
42ExpandedSubBlockEnd.gif  }
43ExpandedBlockEnd.gif}
;
44
None.gif
45
ExpandedBlockStart.gifContractedBlock.gif
class
 IGenericBase 
dot.gif
{
46InBlock.gifpublic:
47InBlock.gif  virtual void func1() = 0;
48ExpandedBlockEnd.gif}
;
49
None.gif
50
ExpandedBlockStart.gifContractedBlock.gif
class
 IGeneric1 : 
public
 IGenericBase 
dot.gif
{
51InBlock.gifpublic:
52InBlock.gif  virtual void func2() = 0;
53ExpandedBlockEnd.gif}
;
54
None.gif
55
ExpandedBlockStart.gifContractedBlock.gif
class
 IGeneric2 : 
public
 IGenericBase 
dot.gif
{
56InBlock.gifpublic:
57InBlock.gif  virtual void func3() = 0;
58ExpandedBlockEnd.gif}
;
59
None.gif
60
None.giftemplate
<
typename T
>
61
ExpandedBlockStart.gifContractedBlock.gif
class
 GenericHandler : 
public
 IGenericBase, IGeneric1, IGeneric2 
dot.gif
{
62InBlock.gifprivate:
63InBlock.gif  T* _aClass;
64InBlock.gif
65InBlock.gifpublic:
66ExpandedSubBlockStart.gifContractedSubBlock.gif  GenericHandler(T* aClass) dot.gif{
67InBlock.gif    _aClass = aClass;
68ExpandedSubBlockEnd.gif  }
69InBlock.gif  
70ExpandedSubBlockStart.gifContractedSubBlock.gif  void func1() dot.gif{
71InBlock.gif    _aClass->func1();
72ExpandedSubBlockEnd.gif  }
73InBlock.gif  
74ExpandedSubBlockStart.gifContractedSubBlock.gif  void func2() dot.gif{
75InBlock.gif    dynamic_cast<Interface1*>(_aClass)->func2();
76ExpandedSubBlockEnd.gif  }
77InBlock.gif  
78ExpandedSubBlockStart.gifContractedSubBlock.gif  void func3() dot.gif{
79InBlock.gif    dynamic_cast<Interface2*>(_aClass)->func3();
80ExpandedSubBlockEnd.gif  }
81ExpandedBlockEnd.gif}
;
82
None.gif
83
ExpandedBlockStart.gifContractedBlock.gif
int
 main() 
dot.gif
{
84InBlock.gif  Interface1* obj1 = new Class1;
85InBlock.gif  Interface2* obj2 = new Class2;
86InBlock.gif  
87InBlock.gif  IGenericBase* foo = new GenericHandler<Interface1>(obj1);
88InBlock.gif  foo->func1();
89InBlock.gif  dynamic_cast<IGeneric1*>(++foo)->func2();
90InBlock.gif  
91InBlock.gif  foo = new GenericHandler<Interface2>(obj2);
92InBlock.gif  foo->func1();
93InBlock.gif  dynamic_cast<IGeneric2*>(++++foo)->func3();
94ExpandedBlockEnd.gif}

執行結果

None.gif
Class1's func1
None.gifClass1's func2
None.gifClass2's func1
None.gifClass2's func3

由於分成Interface1和Interface2,所以GenericHandler的Interface也分成Generic1和Generic2。因為func1()為IGeneric1和IGeneric2共用,所以向上提升到IGenericBase,如此設計有兩個好處:
1.GenericHandler有IGenericBase這個最上層的interface,因此可以配合眾多creational pattern合作。
2.要使用func2()時必須明確轉型成IGeneric1,要使用func3()時必須明確轉型成IGeneric2,如此可避免client誤用而導致run-time error。
若用ISO C++實做,89行和93行非常tricky。

None.gif
dynamic_cast
<
IGeneric1
*>
(
++
foo)
->
func2();
None.gif
dynamic_cast
<
IGeneric2
*>
(
++++
foo)
->
func3();

為什麼要++foo和++++foo呢?
因為在87行

None.gif
IGenericBase
*
 foo 
=
 
new
 GenericHandler
<
Interface1
>
(obj1);

foo是一個指向IGenericBase的pointer,若要casting成指向IGeneric1的pointer,其中有offset存在,所以必須++foo,若要指向IGeneric2,其offset是++++foo,詳細原理在Stanley B. Lippman的大作Inside the C++ Object Model有解釋。
C#

ExpandedBlockStart.gif
ContractedBlock.gif
/**/
/* 
InBlock.gif(C) OOMusou 2007 
http://oomusou.cnblogs.com
InBlock.gif
InBlock.gifFilename    : Generics_SupportMultiInterface2.cs
InBlock.gifCompiler    : Visual Studio 2005 / C# 2.0
InBlock.gifDescription : Demo how to support multiple interface in Generics
InBlock.gifRelease     : 06/17/2007 1.0
ExpandedBlockEnd.gif
*/
None.gif
using
 System;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 InterfaceBase 
dot.gif
{
InBlock.gif  
void func1();
ExpandedBlockEnd.gif}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 Interface1 : InterfaceBase 
dot.gif
{
InBlock.gif  
void func2();
ExpandedBlockEnd.gif}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 Interface2 : InterfaceBase 
dot.gif
{
InBlock.gif  
void func3();
ExpandedBlockEnd.gif}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public
 
class
 Class1 : Interface1 
dot.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void func1() dot.gif{
InBlock.gif    Console.WriteLine(
"Class1's func1");
ExpandedSubBlockEnd.gif  }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void func2() dot.gif{
InBlock.gif    Console.WriteLine(
"Class1's func2");
ExpandedSubBlockEnd.gif  }
ExpandedBlockEnd.gif}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public
 
class
 Class2 : Interface2 
dot.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void func1() dot.gif{
InBlock.gif    Console.WriteLine(
"Class2's func1");
ExpandedSubBlockEnd.gif  }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void func3() dot.gif{
InBlock.gif    Console.WriteLine(
"Class2's func3");
ExpandedSubBlockEnd.gif  }
ExpandedBlockEnd.gif}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 IGenericBase 
dot.gif
{
InBlock.gif  
void func1();
ExpandedBlockEnd.gif}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 IGeneric1 : IGenericBase 
dot.gif
{
InBlock.gif  
void func2();
ExpandedBlockEnd.gif}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 IGeneric2 : IGenericBase 
dot.gif
{
InBlock.gif  
void func3();
ExpandedBlockEnd.gif}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public
 
class
 GenericHandler
<
T
>
 : IGenericBase, IGeneric1, IGeneric2 where T : InterfaceBase 
dot.gif
{
InBlock.gif  
private T _aClass;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public GenericHandler(T aClass) dot.gif{
InBlock.gif    _aClass 
= aClass;
ExpandedSubBlockEnd.gif  }
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void func1() dot.gif{
InBlock.gif    _aClass.func1();
ExpandedSubBlockEnd.gif  }
InBlock.gif  
ExpandedSubBlockStart.gifContractedSubBlock.gif  
void IGeneric1.func2() dot.gif{
InBlock.gif    ((Interface1)_aClass).func2();
ExpandedSubBlockEnd.gif  }
InBlock.gif  
ExpandedSubBlockStart.gifContractedSubBlock.gif  
void IGeneric2.func3() dot.gif{
InBlock.gif    ((Interface2)_aClass).func3();
ExpandedSubBlockEnd.gif  }
ExpandedBlockEnd.gif}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public
 
class
 main 
dot.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public static void Main() dot.gif{
InBlock.gif    Interface1 obj1 
= new Class1();
InBlock.gif    Interface2 obj2 
= new Class2();
InBlock.gif
InBlock.gif    IGenericBase foo 
= new GenericHandler<Interface1>(obj1);
InBlock.gif    foo.func1();
InBlock.gif    ((IGeneric1)foo).func2();
InBlock.gif    
InBlock.gif    foo 
= new GenericHandler<Interface2>(obj2);
InBlock.gif    foo.func1();
InBlock.gif    ((IGeneric2)foo).func3();
ExpandedSubBlockEnd.gif  }
ExpandedBlockEnd.gif}

執行結果

None.gif
Class1's func1
None.gifClass1's func2
None.gifClass2's func1
None.gifClass2's func3

和ISO C++的想法相同,但C#在casting方面就不需考慮offset的問題,且僅使用了C-style的casting。
C++/CLI
使用template

 1
ExpandedBlockStart.gif
ContractedBlock.gif
/**/
/*
 
 2
InBlock.gif(C) OOMusou 2006 
http://oomusou.cnblogs.com
 3
InBlock.gif
 4
InBlock.gifFilename    : Template_SupportMutipleInterface2.cpp
 5
InBlock.gifCompiler    : Visual C++ 8.0 / C++/CLI
 6
InBlock.gifDescription : Demo how to support multiple interface in Generics
 7
InBlock.gifRelease     : 06/18/2007 1.0
 8
ExpandedBlockEnd.gif
*/
 9
None.gif#include 
"
stdafx.h
"
10
None.gif
11
None.gif
using
 
namespace
 System;
12
None.gif
13
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 Interface1 
dot.gif
{
14InBlock.gif  void func1();
15InBlock.gif  void func2();
16ExpandedBlockEnd.gif}
;
17
None.gif
18
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 Interface2 
dot.gif
{
19InBlock.gif  void func1();
20InBlock.gif  void func3();
21ExpandedBlockEnd.gif}
;
22
None.gif
23
ExpandedBlockStart.gifContractedBlock.gif
public
 
ref
 
class
 Class1 : 
public
 Interface1 
dot.gif
{
24InBlock.gifpublic:
25ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func1() dot.gif{
26InBlock.gif    Console::WriteLine("Class1's func1");
27ExpandedSubBlockEnd.gif  }
28InBlock.gif  
29ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func2() dot.gif{
30InBlock.gif    Console::WriteLine("Class1's func2");
31ExpandedSubBlockEnd.gif  }
32ExpandedBlockEnd.gif}
;
33
None.gif
34
ExpandedBlockStart.gifContractedBlock.gif
public
 
ref
 
class
 Class2 : 
public
 Interface2 
dot.gif
{
35InBlock.gifpublic:
36ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func1() dot.gif{
37InBlock.gif    Console::WriteLine("Class2's func1");
38ExpandedSubBlockEnd.gif  }
39InBlock.gif  
40ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func3() dot.gif{
41InBlock.gif    Console::WriteLine("Class2's func3");
42ExpandedSubBlockEnd.gif  }
43ExpandedBlockEnd.gif}
;
44
None.gif
45
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 IGenericBase 
dot.gif
{
46InBlock.gif  void func1();
47ExpandedBlockEnd.gif}
;
48
None.gif
49
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 IGeneric1 : 
public
 IGenericBase 
dot.gif
{
50InBlock.gif  void func2();
51ExpandedBlockEnd.gif}
;
52
None.gif
53
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 IGeneric2 : 
public
 IGenericBase 
dot.gif
{
54InBlock.gif  void func3();
55ExpandedBlockEnd.gif}
;
56
None.gif
57
None.giftemplate
<
typename T
>
58
ExpandedBlockStart.gifContractedBlock.gif
public
 
ref
 
class
 GenericHandler : IGenericBase, IGeneric1, IGeneric2 
dot.gif
{
59InBlock.gifprivate:
60InBlock.gif  T^ _aClass;
61InBlock.gif
62InBlock.gifpublic:
63ExpandedSubBlockStart.gifContractedSubBlock.gif  GenericHandler(T^ aClass) dot.gif{
64InBlock.gif    _aClass = aClass;
65ExpandedSubBlockEnd.gif  }
66InBlock.gif
67ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func1() dot.gif{
68InBlock.gif    _aClass->func1();
69ExpandedSubBlockEnd.gif  }
70InBlock.gif  
71ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func2() = IGeneric1::func2 dot.gif{
72InBlock.gif    safe_cast<Interface1^>(_aClass)->func2();
73ExpandedSubBlockEnd.gif  }
74InBlock.gif  
75ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func3() = IGeneric2::func3 dot.gif{
76InBlock.gif    safe_cast<Interface2^>(_aClass)->func3();
77ExpandedSubBlockEnd.gif  }
78ExpandedBlockEnd.gif}
;
79
None.gif
80
ExpandedBlockStart.gifContractedBlock.gif
int
 main() 
dot.gif
{
81InBlock.gif  Interface1^ obj1 = gcnew Class1;
82InBlock.gif  Interface2^ obj2 = gcnew Class2;
83InBlock.gif  
84InBlock.gif  IGenericBase^ foo = gcnew GenericHandler<Interface1>(obj1);
85InBlock.gif  foo->func1();
86InBlock.gif  safe_cast<IGeneric1^>(foo)->func2();
87InBlock.gif  
88InBlock.gif  foo = gcnew GenericHandler<Interface2>(obj2);
89InBlock.gif  foo->func1();
90InBlock.gif  safe_cast<IGeneric2^>(foo)->func3();
91ExpandedBlockEnd.gif}

執行結果

None.gif
Class1's func1
None.gifClass1's func2
None.gifClass2's func1
None.gifClass2's func3

想法也和ISO C++和C#相同,不過在語法細節上,C++/CLI在casting和explicit interface implementation上和ISO C++與C#不同。
1.casting
72行

None.gif
safe_cast
<
Interface1
^>
(_aClass)
->
func2();

ISO C++在casting上有const_cast,dynamic_cast,reinterpret_cast和static_cast,在C++/CLI仍然可用,除此之外,C++/CLI另外提出了safe_cast,專門應付managed部分。
2.explicit interface implementation
71行

ExpandedBlockStart.gif
ContractedBlock.gif
virtual
 
void
 func2() 
=
 IGeneric1::func2 
dot.gif
{

就是C#的

ExpandedBlockStart.gif
ContractedBlock.gif
void
 IGeneric1.func2() 
dot.gif
{

ISO C++並沒有這樣的語法,這是.NET CLI規格新加上去的。
使用generics

 1
ExpandedBlockStart.gif
ContractedBlock.gif
/**/
/*
 
 2
InBlock.gif(C) OOMusou 2006 
http://oomusou.cnblogs.com
 3
InBlock.gif
 4
InBlock.gifFilename    : Generic_SupportMutipleInterface2.cpp
 5
InBlock.gifCompiler    : Visual C++ 8.0 / C++/CLI
 6
InBlock.gifDescription : Demo how to support multiple interface in Generics
 7
InBlock.gifRelease     : 06/16/2007 1.0
 8
ExpandedBlockEnd.gif
*/
 9
None.gif#include 
"
stdafx.h
"
10
None.gif
11
None.gif
using
 
namespace
 System;
12
None.gif
13
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 InterfaceBase 
dot.gif
{
14InBlock.gif  void func1();
15ExpandedBlockEnd.gif}
;
16
None.gif
17
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 Interface1 : InterfaceBase 
dot.gif
{
18InBlock.gif  void func2();
19ExpandedBlockEnd.gif}
;
20
None.gif
21
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 Interface2 : InterfaceBase 
dot.gif
{
22InBlock.gif  void func3();
23ExpandedBlockEnd.gif}
;
24
None.gif
25
ExpandedBlockStart.gifContractedBlock.gif
public
 
ref
 
class
 Class1 : 
public
 Interface1 
dot.gif
{
26InBlock.gifpublic:
27ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func1() dot.gif{
28InBlock.gif    Console::WriteLine("Class1's func1");
29ExpandedSubBlockEnd.gif  }
30InBlock.gif  
31ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func2() dot.gif{
32InBlock.gif    Console::WriteLine("Class1's func2");
33ExpandedSubBlockEnd.gif  }
34ExpandedBlockEnd.gif}
;
35
None.gif
36
ExpandedBlockStart.gifContractedBlock.gif
public
 
ref
 
class
 Class2 : 
public
 Interface2 
dot.gif
{
37InBlock.gifpublic:
38ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func1() dot.gif{
39InBlock.gif    Console::WriteLine("Class2's func1");
40ExpandedSubBlockEnd.gif  }
41InBlock.gif  
42ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func3() dot.gif{
43InBlock.gif    Console::WriteLine("Class2's func3");
44ExpandedSubBlockEnd.gif  }
45ExpandedBlockEnd.gif}
;
46
None.gif
47
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 IGenericBase 
dot.gif
{
48InBlock.gif  void func1();
49ExpandedBlockEnd.gif}
;
50
None.gif
51
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 IGeneric1 : 
public
 IGenericBase 
dot.gif
{
52InBlock.gif  void func2();
53ExpandedBlockEnd.gif}
;
54
None.gif
55
ExpandedBlockStart.gifContractedBlock.gif
public
 
interface
 
class
 IGeneric2 : 
public
 IGenericBase 
dot.gif
{
56InBlock.gif  void func3();
57ExpandedBlockEnd.gif}
;
58
None.gif
59
None.gifgeneric
<
typename T
>
 
60
None.gif  where T : InterfaceBase
61
ExpandedBlockStart.gifContractedBlock.gif
public
 
ref
 
class
 GenericHandler : IGenericBase, IGeneric1, IGeneric2 
dot.gif
{
62InBlock.gifprivate:
63InBlock.gif  T _aClass;
64InBlock.gif  
65InBlock.gifpublic:
66ExpandedSubBlockStart.gifContractedSubBlock.gif  GenericHandler(T aClass) dot.gif{
67InBlock.gif    _aClass = aClass;
68ExpandedSubBlockEnd.gif  }
69InBlock.gif
70ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func1() dot.gif{
71InBlock.gif    _aClass->func1();
72ExpandedSubBlockEnd.gif  }
73InBlock.gif  
74ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func2() = IGeneric1::func2 dot.gif{
75InBlock.gif    safe_cast<Interface1^>(_aClass)->func2();
76ExpandedSubBlockEnd.gif  }
77InBlock.gif  
78ExpandedSubBlockStart.gifContractedSubBlock.gif  virtual void func3() = IGeneric2::func3 dot.gif{
79InBlock.gif    safe_cast<Interface2^>(_aClass)->func3();
80ExpandedSubBlockEnd.gif  }
81ExpandedBlockEnd.gif}
;
82
None.gif
83
ExpandedBlockStart.gifContractedBlock.gif
int
 main() 
dot.gif
{
84InBlock.gif  Interface1^ obj1 = gcnew Class1;
85InBlock.gif  Interface2^ obj2 = gcnew Class2;
86InBlock.gif  
87InBlock.gif  IGenericBase^ foo = gcnew GenericHandler<Interface1^>(obj1);
88InBlock.gif  foo->func1();
89InBlock.gif  safe_cast<IGeneric1^>(foo)->func2();
90InBlock.gif  
91InBlock.gif  foo = gcnew GenericHandler<Interface2^>(obj2);
92InBlock.gif  foo->func1();
93InBlock.gif  safe_cast<IGeneric2^>(foo)->func3();
94ExpandedBlockEnd.gif}

C++/CLI若使用generics寫,其實在此範例看不出template和generics的差異,唯一就是在generics需要constraints。

Conclusion

經過幾天的折騰,總算找出了還算滿意的方式,尤其是ISO C++的offset和C++/CLI的explicit interface implementation讓我印象深刻,另外一個遺憾的是,似乎沒用到什麼Design Pattern,只是憑直覺去思考,若有任何建議都非常歡迎。

转载地址:http://xquqa.baihongyu.com/

你可能感兴趣的文章
UNIX进程环境
查看>>
我最喜欢的jQuery插件模板
查看>>
【云计算】Docker 多进程管理方案
查看>>
[LeetCode] Best Meeting Point 最佳开会地点
查看>>
基于InstallShield2013LimitedEdition的安装包制作
查看>>
【转】从Shell脚本内部将所有标准输出及标准错误显示在屏幕并同时写入文件的方法...
查看>>
Python中的图形库
查看>>
Linux操作系统分析 ------------------中国科技大学
查看>>
Apache多站点实现原理和配置
查看>>
javascript类型系统——包装对象
查看>>
Android4.4中不能发送SD卡就绪广播
查看>>
解决:sudo: 无法解析主机:dinphy-500-310cn: 连接超时
查看>>
Asp.Net多线程用法1
查看>>
exFAT是支持Mac和Win的
查看>>
(转)postman中 form-data、x-www-form-urlencoded、raw、binary的区别
查看>>
js Date操作
查看>>
判断用户密码是否在警告期内(学习练习)
查看>>
sp_executesql的执行计划会被重用(转载)
查看>>
禅道项目管理软件插件开发
查看>>
Linux系统各发行版镜像下载
查看>>