제네릭 클래스(C++/CLI)
제네릭클래스는 다음과 같은양식사용 하 여 선언 됩니다.
[attributes]
generic <class-key type-parameter-identifier(s)>
[constraint-clauses]
[accessibility-modifiers] ref class identifier [modifiers]
[: base-list]
{
class-body
} [declarators] [;]
설명
위의 구문에는 다음과 같은 용어가 사용 됩니다.
attributes(선택적 요소)
추가 선언 정보입니다.특성 및특성클래스에 대 한 자세한 내용은 특성을 참조 하십시오.클래스-키
어느 class 또는typename형식매개 변수-식별자(s),
쉼표로 구분 된 목록 형식 매개 변수의 이름을 지정 하는 식별자입니다.제약 조건-절
목록 (쉼표로 구분 없는) 는 의 형식 매개 변수 제약 조건을 지정 하는 절.양식을 사용합니다.where 형식매개 변수-식별자 : 제약 조건-목록 ...
제약 조건-목록
클래스-or-인터페이스, ...접근성-한정자
제네릭클래스에 대 한 액세스 가능성 한정자입니다.에 Windows 런타임에 한정자를 사용할 수 있습니다 private.허용 된 한정자에 대 한공용 언어 런타임, 제공 되는 private 및 public.identifier
제네릭클래스,유효한C++식별자의 이름입니다.한정자 (옵션)
한정자를 포함 수 sealed 및 추상.자료 목록
하나기본 클래스와 모든 목록을 쉼표로 구분 된 모든 인터페이스를 구현 합니다.클래스-본문
본문 필드, 멤버 함수 등을 포함 하는클래스입니다.선언 자
이 형식의 변수를 선언 합니다.For example: ^식별자, ...]
이러한 제네릭 클래스를선언하다수 있습니다 (참고키워드클래스 대신 사용 될 수 있습니다 유형 이름). 이 예제에서 ItemType, KeyType 및 ValueType 지점에 지정 된 알 수 없는 형식입니다 위치 형식입니다.HashTable<int, int>생성 된 형식인제네릭 형식HashTable<KeyType, ValueType>.단일제네릭 형식에서 여러 가지 다른 구성 된 형식 생성할 수 있습니다.생성 된 형식은 제네릭 클래스에서 생성 된 다른 ref클래스형식과 마찬가지로 취급 됩니다.
// generic_classes_1.cpp
// compile with: /clr
using namespace System;
generic <typename ItemType>
ref struct Stack {
// ItemType may be used as a type here
void Add(ItemType item) {}
};
generic <typename KeyType, typename ValueType>
ref class HashTable {};
// The keyword class may be used instead of typename:
generic <class ListItem>
ref class List {};
int main() {
HashTable<int, Decimal>^ g1 = gcnew HashTable<int, Decimal>();
}
모두 값 형식 (두 기본 제공 형식으로 int 또는 double, 또는사용자-값 형식 정의) 및 참조 형식인수제네릭 형식사용할 수 있습니다. 제네릭 정의에서 구문에 관계 없이 동일합니다.구문적으로 알 수 없는 유형참조 형식것 처럼 처리 됩니다.그러나런타임실제로 사용 되는값 형식입니다 경우 확인 하 고 멤버직접 액세스에 대 한 적절 한 생성 된코딩하다대신 사용할 수 있습니다.제네릭 형식인수로 사용 되는 값 형식을 박스형 되지 않습니다 및 따라서boxing와 관련 된성능저하가 발생 하지 않습니다.일반 본문에 사용 된 구문 이어야 합니다 T ^ 와 '->' 대신 '.'.모든 사용에 ref new, gcnew(C++ 구성 요소 확장)값 형식형식인수있는 경우 형식에 대 한매개 변수적절 하 게런타임간단한 작성을값 형식으로 해석 됩니다.
또한선언하다수 있는 제네릭클래스있습니다 제네릭 형식 매개 변수에 대한 제약 조건(C++/CLI) 형식에 대 한 형식매개 변수를 사용할 수 있습니다.다음 예제에서는 모든 형식의 사용 ItemType 구현 해야는 IItem인터페이스입니다. 사용 하는 int, 예를 들어, 어떤 되지 않습니다 구현 IItem, 발생 한컴파일하다-형식인수제약 조건을 만족 하지 않는 때문에오류시간.
// generic_classes_2.cpp
// compile with: /clr /c
interface class IItem {};
generic <class ItemType>
where ItemType : IItem
ref class Stack {};
동일한네임스페이스의 제네릭 클래스 또는 형식 매개 변수의 형식을 변경 하면 오버 로드할 수 없습니다.오버 각클래스네임스페이스와 다른 경우, 이들은 로드할 수 있습니다.예를 들어, 다음 두 개의 클래스, 고려 MyClass 및 MyClass<ItemType>, 네임 스페이스의 A 및 B.두 클래스는 다음 세 번째네임스페이스에서는 c: 오버 로드할 수 있습니다.
// generic_classes_3.cpp
// compile with: /clr /c
namespace A {
ref class MyClass {};
}
namespace B {
generic <typename ItemType>
ref class MyClass2 { };
}
namespace C {
using namespace A;
using namespace B;
ref class Test {
static void F() {
MyClass^ m1 = gcnew MyClass(); // OK
MyClass2<int>^ m2 = gcnew MyClass2<int>(); // OK
}
};
}
기본 클래스및 기본 인터페이스 형식 매개 변수 여야 합니다.그러나기본 클래스형식매개 변수인수를 다음과 같은대/소문자에 필요할 수 있습니다.
// generic_classes_4.cpp
// compile with: /clr /c
generic <typename ItemType>
interface class IInterface {};
generic <typename ItemType>
ref class MyClass : IInterface<ItemType> {};
생성자와 소멸자가 한 번 각개체인스턴스에 대 한 (일반적으로); 실행 됩니다. 고정적인생성자는 한 번 생성 된 각 형식에 대해 실행 됩니다.
제네릭 클래스의 필드
이 단원에서는 제네릭 클래스의 인스턴스 및고정적인필드를 사용 하는 방법을 보여 줍니다.
인스턴스 변수
제네릭클래스의 인스턴스 변수 형식과 바깥쪽클래스의 형식 매개 변수를 포함 하는변수이니셜라이저를 가질 수 있습니다.
예제
다음 예제에서는 해당 형식 인수를 사용 하 여 제네릭클래스MyClass <ItemType>의 여러 인스턴스를 세 개 만든 (int, 이중, 및 문자열).
// generics_instance_fields1.cpp
// compile with: /clr
// Instance fields on generic classes
using namespace System;
generic <typename ItemType>
ref class MyClass {
// Field of the type ItemType:
public :
ItemType field1;
// Constructor using a parameter of the type ItemType:
MyClass(ItemType p) {
field1 = p;
}
};
int main() {
// Instantiate an instance with an integer field:
MyClass<int>^ myObj1 = gcnew MyClass<int>(123);
Console::WriteLine("Integer field = {0}", myObj1->field1);
// Instantiate an instance with a double field:
MyClass<double>^ myObj2 = gcnew MyClass<double>(1.23);
Console::WriteLine("Double field = {0}", myObj2->field1);
// Instantiate an instance with a String field:
MyClass<String^>^ myObj3 = gcnew MyClass<String^>("ABC");
Console::WriteLine("String field = {0}", myObj3->field1);
}
다음 예제에서는고정적인필드 및고정적인생성자는 제네릭클래스내에서 사용 하는 방법을 보여 줍니다.
// generics_static2.cpp
// compile with: /clr
using namespace System;
interface class ILog {
void Write(String^ s);
};
ref class DateTimeLog : ILog {
public:
virtual void Write(String^ s) {
Console::WriteLine( "{0}\t{1}", DateTime::Now, s);
}
};
ref class PlainLog : ILog {
public:
virtual void Write(String^ s) { Console::WriteLine(s); }
};
generic <typename LogType>
where LogType : ILog
ref class G {
static LogType s_log;
public:
G(){}
void SetLog(LogType log) { s_log = log; }
void F() { s_log->Write("Test1"); }
static G() { Console::WriteLine("Static constructor called."); }
};
int main() {
G<PlainLog^>^ g1 = gcnew G<PlainLog^>();
g1->SetLog(gcnew PlainLog());
g1->F();
G<DateTimeLog^>^ g2 = gcnew G<DateTimeLog^>();
g2->SetLog(gcnew DateTimeLog());
// prints date
// g2->F();
}
다음 예제는 비 선언-제네릭 메서드를 ProtectData, 제네릭클래스, MyClass<ItemType>.메서드클래스형식매개 변수를 사용 하 여ItemType서명부분에는시작됨유형을 구성 합니다.
// generics_non_generic_methods1.cpp
// compile with: /clr
// Non-generic methods within a generic class.
using namespace System;
generic <typename ItemType>
ref class MyClass {
public:
String^ name;
ItemType data;
MyClass(ItemType x) {
data = x;
}
// Non-generic method using the type parameter:
virtual void ProtectData(MyClass<ItemType>^ x) {
data = x->data;
}
};
// ItemType defined as String^
ref class MyMainClass: MyClass<String^> {
public:
// Passing "123.00" to the constructor:
MyMainClass(): MyClass<String^>("123.00") {
name = "Jeff Smith";
}
virtual void ProtectData(MyClass<String^>^ x) override {
x->data = String::Format("${0}**", x->data);
}
static void Main() {
MyMainClass^ x1 = gcnew MyMainClass();
x1->ProtectData(x1);
Console::WriteLine("Name: {0}", x1->name);
Console::WriteLine("Amount: {0}", x1->data);
}
};
int main() {
MyMainClass::Main();
}
// generics_method2.cpp
// compile with: /clr /c
generic <typename Type1>
ref class G {
public:
// Generic method having a type parameter
// from the class, Type1, and its own type
// parameter, Type2
generic <typename Type2>
void Method1(Type1 t1, Type2 t2) { F(t1, t2); }
// Non-generic method:
// Can use the class type param, Type1, but not Type2.
void Method2(Type1 t1) { F(t1, t1); }
void F(Object^ o1, Object^ o2) {}
};
비-제네릭 메서드는클래스의 형식매개 변수, 매개 변수화 된 있지만 추가 형식 매개 변수가 없는 점에서 여전히 제네릭입니다.
모든 형식의 제네릭 클래스 메서드와 제네릭고정적인, 인스턴스 및 가상 메서드를 비롯 하 여 수 있습니다.
다음 예제에서는 선언 및 제네릭 클래스 내에서 제네릭 메서드를 사용 하는 방법을 보여 줍니다.
// generics_generic_method2.cpp
// compile with: /clr
using namespace System;
generic <class ItemType>
ref class MyClass {
public:
// Declare a generic method member.
generic <class Type1>
String^ MyMethod(ItemType item, Type1 t) {
return String::Concat(item->ToString(), t->ToString());
}
};
int main() {
// Create instances using different types.
MyClass<int>^ myObj1 = gcnew MyClass<int>();
MyClass<String^>^ myObj2 = gcnew MyClass<String^>();
MyClass<String^>^ myObj3 = gcnew MyClass<String^>();
// Calling MyMethod using two integers.
Console::WriteLine("MyMethod returned: {0}",
myObj1->MyMethod<int>(1, 2));
// Calling MyMethod using an integer and a string.
Console::WriteLine("MyMethod returned: {0}",
myObj2->MyMethod<int>("Hello #", 1));
// Calling MyMethod using two strings.
Console::WriteLine("MyMethod returned: {0}",
myObj3->MyMethod<String^>("Hello ", "World!"));
// generic methods can be called without specifying type arguments
myObj1->MyMethod<int>(1, 2);
myObj2->MyMethod<int>("Hello #", 1);
myObj3->MyMethod<String^>("Hello ", "World!");
}
// generics_linked_list.cpp
// compile with: /clr
using namespace System;
generic <class ItemType>
ref class LinkedList {
// The node class:
public:
ref class Node {
// The link field:
public:
Node^ next;
// The data field:
ItemType item;
} ^first, ^current;
};
ref class ListBuilder {
public:
void BuildIt(LinkedList<double>^ list) {
/* Build the list */
double m[5] = {0.1, 0.2, 0.3, 0.4, 0.5};
Console::WriteLine("Building the list:");
for (int n=0; n<=4; n++) {
// Create a new node:
list->current = gcnew LinkedList<double>::Node();
// Assign a value to the data field:
list->current->item = m[n];
// Set the link field "next" to be the same as
// the "first" field:
list->current->next = list->first;
// Redirect "first" to the new node:
list->first = list->current;
// Display node's data as it builds:
Console::WriteLine(list->current->item);
}
}
void ReadIt(LinkedList<double>^ list) {
// Read the list
// Make "first" the "current" link field:
list->current = list->first;
Console::WriteLine("Reading nodes:");
// Read nodes until current == null:
while (list->current != nullptr) {
// Display the node's data field:
Console::WriteLine(list->current->item);
// Move to the next node:
list->current = list->current->next;
}
}
};
int main() {
// Create a list:
LinkedList<double>^ aList = gcnew LinkedList<double>();
// Initialize first node:
aList->first = nullptr;
// Instantiate the class, build, and read the list:
ListBuilder^ myListBuilder = gcnew ListBuilder();
myListBuilder->BuildIt(aList);
myListBuilder->ReadIt(aList);
}
제네릭클래스내에서 인스턴스속성을 선언 하는 예제입니다.
// generics_generic_properties1.cpp
// compile with: /clr
using namespace System;
generic <typename ItemType>
ref class MyClass {
private:
property ItemType myField;
public:
property ItemType MyProperty {
ItemType get() {
return myField;
}
void set(ItemType value) {
myField = value;
}
}
};
int main() {
MyClass<String^>^ c = gcnew MyClass<String^>();
MyClass<int>^ c1 = gcnew MyClass<int>();
c->MyProperty = "John";
c1->MyProperty = 234;
Console::Write("{0}, {1}", c->MyProperty, c1->MyProperty);
}
다음 예제에서는이벤트를 사용 하 여 제네릭클래스를 보여 줍니다.
// generics_generic_with_event.cpp
// compile with: /clr
// Declare a generic class with an event and
// invoke events.
using namespace System;
// declare delegates
generic <typename ItemType>
delegate void ClickEventHandler(ItemType);
// generic class that defines events
generic <typename ItemType>
ref class EventSource {
public:
// declare the event OnClick
event ClickEventHandler<ItemType>^ OnClick;
void FireEvents(ItemType item) {
// raises events
OnClick(item);
}
};
// generic class that defines methods that will called when
// event occurs
generic <typename ItemType>
ref class EventReceiver {
public:
void OnMyClick(ItemType item) {
Console::WriteLine("OnClick: {0}", item);
}
};
int main() {
EventSource<String^>^ MyEventSourceString =
gcnew EventSource<String^>();
EventSource<int>^ MyEventSourceInt = gcnew EventSource<int>();
EventReceiver<String^>^ MyEventReceiverString =
gcnew EventReceiver<String^>();
EventReceiver<int>^ MyEventReceiverInt = gcnew EventReceiver<int>();
// hook handler to event
MyEventSourceString->OnClick += gcnew ClickEventHandler<String^>(
MyEventReceiverString, &EventReceiver<String^>::OnMyClick);
MyEventSourceInt->OnClick += gcnew ClickEventHandler<int>(
MyEventReceiverInt, &EventReceiver<int>::OnMyClick);
// invoke events
MyEventSourceString->FireEvents("Hello");
MyEventSourceInt->FireEvents(112);
// unhook handler to event
MyEventSourceString->OnClick -= gcnew ClickEventHandler<String^>(
MyEventReceiverString, &EventReceiver<String^>::OnMyClick);
MyEventSourceInt->OnClick -= gcnew ClickEventHandler<int>(
MyEventReceiverInt, &EventReceiver<int>::OnMyClick);
}
다음 예제에서는 제네릭구조체를 선언 MyGenStruct, 하나의필드와 myField, 다양 한 종류의 값을 할당 하 고 (int, 이중, 문자열 ^)이필드에.
// generics_generic_struct1.cpp
// compile with: /clr
using namespace System;
generic <typename ItemType>
ref struct MyGenStruct {
public:
ItemType myField;
ItemType AssignValue(ItemType item) {
myField = item;
return myField;
}
};
int main() {
int myInt = 123;
MyGenStruct<int>^ myIntObj = gcnew MyGenStruct<int>();
myIntObj->AssignValue(myInt);
Console::WriteLine("The field is assigned the integer value: {0}",
myIntObj->myField);
double myDouble = 0.123;
MyGenStruct<double>^ myDoubleObj = gcnew MyGenStruct<double>();
myDoubleObj->AssignValue(myDouble);
Console::WriteLine("The field is assigned the double value: {0}",
myDoubleObj->myField);
String^ myString = "Hello Generics!";
MyGenStruct<String^>^ myStringObj = gcnew MyGenStruct<String^>();
myStringObj->AssignValue(myString);
Console::WriteLine("The field is assigned the string: {0}",
myStringObj->myField);
}
정적 변수
만들기 새제네릭 형식에고정적인변수의 새 인스턴스가 만들어지지 않습니다 및 해당 형식에 대 한고정적인생성자를 실행 합니다.
정적 변수는 바깥쪽클래스의 형식 매개 변수를 사용할 수 있습니다.
제네릭 클래스의 메서드
제네릭 클래스의 메서드와 제네릭 수 있습니다 스스로. 제네릭이 아닌 메서드클래스형식매개 변수변수로 암시적으로 매개 변수화 됩니다.
다음과 같은 특수 규칙을 제네릭 클래스의 메서드적용하다합니다.
제네릭 클래스의 메서드와 형식 매개 변수에 매개 변수, 반환 형식 또는 로컬 변수 이름으로 사용할 수 있습니다.
제네릭 클래스의 메서드를시작됨수 있습니다 또는 생성 된 형식 매개 변수, 반환 형식 또는 로컬 변수 이름으로 폐쇄.
제네릭 클래스의 제네릭이 아닌 메서드
추가 형식 매개 변수가 있는 제네릭 클래스의 메서드가 바깥쪽 제네릭클래스는 암시적으로 매개 변수화 하는 있지만 일반적으로 제네릭이으로 라고 합니다.
비의서명-제네릭 메서드포함 하나 또는 더 많은 형식 매개 변수는 바깥쪽클래스에서 직접 또는시작됨생성 된 형식입니다.예를 들면 다음과 같습니다.
void MyMethod(MyClass<ItemType> x) {}
이러한 메서드의 본문 이러한 형식 매개 변수를 사용할 수도 있습니다.
제네릭 클래스의 제네릭 메서드
제네릭 및 제네릭이 아닌 클래스에서 제네릭 메서드를선언하다수 있습니다.예를 들면 다음과 같습니다.
중첩된 형식의 제네릭 클래스를 사용 하 여
마찬가지로 일반 클래스와선언하다다른 형식의 제네릭클래스내에서 가능합니다.중첩된클래스선언암시적으로 외부클래스선언형식 매개 변수에서 매개 변수화 됩니다.따라서 중첩 된클래스에 각 구성 된 외부 형식에 대해 정의 됩니다.예를 들어,선언에서
// generic_classes_5.cpp
// compile with: /clr /c
generic <typename ItemType>
ref struct Outer {
ref class Inner {};
};
<int> 외부 형식:: 내부 없는 형식과 외부 <double>:: 내부.
제네릭 클래스의 제네릭 메서드와 함께 추가 형식 매개 변수중첩 형식에 대해 정의할 수 있습니다.내부 및 외부클래스에서 동일한 형식매개 변수이름을 사용 하는 경우매개 변수내부 형식매개 변수외부 형식 합니다숨기다.
// generic_classes_6.cpp
// compile with: /clr /c
generic <typename ItemType>
ref class Outer {
ItemType outer_item; // refers to outer ItemType
generic <typename ItemType>
ref class Inner {
ItemType inner_item; // refers to Inner ItemType
};
};
바깥쪽 형식의매개 변수를 참조할 수 있는 방법이 없으므로컴파일러이 상황에서경고를 생성 합니다.
생성 된 중첩 된 제네릭 형식 이름을 지정 하는 경우 내부 형식을 암시적으로 바깥쪽 형식의 형식매개 변수에서 매개 변수화 된 경우에 바깥쪽 형식의 형식매개 변수는 내부 형식에 대해 형식매개 변수목록에 포함 되지 않습니다.위대/소문자에서 생성 된 형식의 이름은 외부 <int> 수 있습니다:: 내부 <string> 합니다.
다음은 빌드 및 중첩된 형식의 제네릭 클래스를 사용 하 여 연결 된 목록을 읽는 방법을 보여 줍니다.
속성, 이벤트, 인덱서 및 연산자의 제네릭 클래스
속성, 이벤트, 인덱서 및 연산자 사용 바깥쪽 제네릭클래스의 형식 매개 변수를 반환 값, 매개 변수, 또는 경우 처럼 지역 변수 ItemType클래스의 형식매개 변수입니다.
public ItemType MyProperty {}
속성, 이벤트, 인덱서 및 연산자는 매개 변수화 할 수 없습니다.
제네릭 구조체
선언 및 제네릭 구조체를 사용 하 여 규칙에서 Visual C++ 언어 참조에서 설명 된 차이점을 제외 하 고 제네릭 클래스에 대 한과 동일 합니다.