다음을 통해 공유


제네릭 클래스(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> {};

생성자와 소멸자가 한 번 각개체인스턴스에 대 한 (일반적으로); 실행 됩니다. 고정적인생성자는 한 번 생성 된 각 형식에 대해 실행 됩니다.

제네릭 클래스의 필드

이 단원에서는 제네릭 클래스의 인스턴스 및고정적인필드를 사용 하는 방법을 보여 줍니다.

skef48fy.collapse_all(ko-kr,VS.110).gif인스턴스 변수

제네릭클래스의 인스턴스 변수 형식과 바깥쪽클래스의 형식 매개 변수를 포함 하는변수이니셜라이저를 가질 수 있습니다.

예제

다음 예제에서는 해당 형식 인수를 사용 하 여 제네릭클래스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);
}
  

정적 변수

만들기 새제네릭 형식에고정적인변수의 새 인스턴스가 만들어지지 않습니다 및 해당 형식에 대 한고정적인생성자를 실행 합니다.

정적 변수는 바깥쪽클래스의 형식 매개 변수를 사용할 수 있습니다.

제네릭 클래스의 메서드

제네릭 클래스의 메서드와 제네릭 수 있습니다 스스로. 제네릭이 아닌 메서드클래스형식매개 변수변수로 암시적으로 매개 변수화 됩니다.

다음과 같은 특수 규칙을 제네릭 클래스의 메서드적용하다합니다.

  • 제네릭 클래스의 메서드와 형식 매개 변수에 매개 변수, 반환 형식 또는 로컬 변수 이름으로 사용할 수 있습니다.

  • 제네릭 클래스의 메서드를시작됨수 있습니다 또는 생성 된 형식 매개 변수, 반환 형식 또는 로컬 변수 이름으로 폐쇄.

skef48fy.collapse_all(ko-kr,VS.110).gif제네릭 클래스의 제네릭이 아닌 메서드

추가 형식 매개 변수가 있는 제네릭 클래스의 메서드가 바깥쪽 제네릭클래스는 암시적으로 매개 변수화 하는 있지만 일반적으로 제네릭이으로 라고 합니다.

비의서명-제네릭 메서드포함 하나 또는 더 많은 형식 매개 변수는 바깥쪽클래스에서 직접 또는시작됨생성 된 형식입니다.예를 들면 다음과 같습니다.

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++ 언어 참조에서 설명 된 차이점을 제외 하 고 제네릭 클래스에 대 한과 동일 합니다.

참고 항목

기타 리소스

제네릭(C++ 구성 요소 확장)