Sdílet prostřednictvím


Obecný tříd (C + +/ CLI)

Obecná třída je deklarována pomocí následujícího formulář:

[attributes]
generic <class-key type-parameter-identifier(s)>
[constraint-clauses]
[accessibility-modifiers] ref class identifier  [modifiers]
[: base-list] 
{
class-body
} [declarators] [;]

Poznámky

V syntaxi výše jsou použity následující termíny:

  • attributes (volitelné)
    Další informace o deklarativní.Další informace o atributů a tříd atribut viz atributy.

  • třída-klíč
    Buď class nebotypename

  • typ -parametr-identifikátor(s),
    Čárkami oddělený seznam identifikátorů zadání názvů parametrů typu.

  • omezení-doložky
    Seznam (není oddělený čárkami) kde klauzule určující omezení pro parametry typu.Má formulář:

    where typ -parametr-identifikátor : omezení-seznam ...

  • omezení-seznam
    třída-or-rozhraní, ...

  • usnadnění-modifikátory
    Modifikátory dostupnosti pro obecná třída.Pro Windows Runtime, povoleny Modifikátor je pouze private.modul CLR (Common Language Runtime)povolených parametrů jsou private a public.

  • identifikátor
    Název Obecné třída, žádné platný C++ identifikátor.

  • Modifikátory (volitelné)
    Mohou zahrnovat modifikátory sealed a abstraktní.

  • Přehled základních
    Seznam, který obsahuje jeden základní třída a jakékoli implementováno rozhraní všech oddělených čárkami.

  • třída-tělo
    Tělo třída, obsahující pole, funkce členů, atd.

  • declarators
    Deklarace proměnných tohoto typu.For example: ^identifikátor, ...]

Můžete deklarovat jako tyto obecné třídy (Všimněte si, že klíčové slovotřída může být použit namísto typename). V tomto příkladu ItemType, KeyType a ValueType jsou neznámé typy, které jsou uvedeny v bodě, kde typ.HashTable<int, int>je vyrobeno typ obecný typ HashTable<KeyType, ValueType>.Počet různých typů vyrobeno lze zkonstruovat z jednoho obecný typ.Vyrobeno typy vyrobeny z obecných tříd jsou zpracovány jako libovolný jiný typ třída 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>();
}

Oba typy hodnot (buď předdefinované typy jako int nebo double, nebo uživatel-definované typy hodnot) a typy odkazovat se může být použit jakoargument obecný typ. Obecná definice syntaxe je stejná bez ohledu na to.Neznámý typ syntakticky, zachází jako kdyby typ odkazovat se .Je však možné určit, zda-li skutečně použitého hodnota a nahradit do generovaného kódu pro přímý přístup členům modulu runtime.Typy hodnot používá jako argumenty obecný typ není boxed a tak nezpůsobuje výkon .Syntaxe používané v rámci obecného těla by měla být T ^ a "->"namísto".'.Použití ref new, gcnew (rozšíření komponent C++) pro typ parametr správně interpretována modulem runtime jako jednoduché vytváření hodnota Pokud je typ argument hodnota.

Můžete také deklarovat obecná třída s Omezení na Obecné zadejte parametry (C + +/ CLI) na typy, které lze použít pro parametrtypu.Následující příklad používá typ pro ItemType musí implementovat IItem rozhraní. Pokouší použít int, například který neimplementuje IItem, vytvoří kompilovat-čas chyba , protože nesplňuje-li v argument typ omezení.

// generic_classes_2.cpp
// compile with: /clr /c
interface class IItem {};
generic <class ItemType>
where ItemType : IItem
ref class Stack {};

Obecný třídy ve stejném obor názvů nesmí být přetížené pouze změnou čísla nebo typy parametrů typu.Však pokud každá třída žije v jiném obor názvů, jejich může být přetížený.Například zvažte následující dvě třídy MyClass a MyClass<ItemType>, v obory názvů A a B.Dvě třídy lze potom přetížení v třetí obor názvů 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
      }
   };
}

Základní třída a základní rozhraní nelze parametry typu.Základní třída však může zahrnovat typ parametr jako argument, jako v případě následující:

// generic_classes_4.cpp
// compile with: /clr /c
generic <typename ItemType>
interface class IInterface {};

generic <typename ItemType>
ref class MyClass : IInterface<ItemType> {};

Konstruktory a destruktory jsou prováděna jednou pro každou instanci objekt (jako obvykle); statický konstruktory spuštěny jednou pro každý typ konstrukce.

Pole Obecné tříd

Tato část ukazuje použití polí instance a statický tříd Obecné.

skef48fy.collapse_all(cs-cz,VS.110).gifProměnné instance

Proměnné instance třída obecný může mít typy a Inicializátory proměnná , které zahrnují všechny parametry typu z vnějšího třída.

Příklad

V následujícím příkladu jsou vytvořeny tři různé instance obecný třídaMoje_třída <ItemType> pomocí vhodného typu argumenty (int, dvojité, a řetězec).

// 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);
   }
  

Následující příklad ukazuje použití statický pole a statický konstruktor v rámci Obecné třída.

// 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();
}
  
  
  
  

Následující příklad prohlašuje než-obecná metoda ProtectData, uvnitř obecná třída MyClass<ItemType>.metoda používá typ třída parametr ItemType v signatura v otevřený vyrobeno typu.

// 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) {}
};

Non-obecná metoda je stále obecný ve smyslu parametrizovanou třídatypu parametr, ale nemá žádné další typ parametry.

Všechny typy tříd obecné metody může být obecný, včetně statický, instance a virtuální metody.

Následující příklad znázorňuje deklarování a použití obecné metody v rámci obecných tříd:

// 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);
}
  

Tento příklad ukazuje prohlášení vlastnost instance v rámci Obecné třída.

// 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);
}
  

Další příklad ukazuje obecná třída s událost.

// 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);
}

Následující příklad prohlašuje obecná struktura MyGenStruct, s jedním pole myFielda přiřadí hodnoty různých typů (int, dvojité, řetězec ^) do tohoto pole.

// 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);
}
  

Statické proměnné

Při vytvoření nového obecný typjsou vytvořeny nové instance žádné statický proměnné a provedení jakékoli statický konstruktor typu.

Statické proměnné lze použít všechny parametry typu z vnějšího třída.

Metody tříd obecný

Může být v metodách tříd obecné obecný; Obecné metody bude implicitně Parametrizovaná třída typ parametr.

Následující zvláštní pravidla párovat metod v rámci obecných tříd:

  • Metody tříd obecné parametry typu lze použít jako parametry, návratové typy nebo lokální proměnné.

  • Metody tříd Obecné lze otevřený nebo uzavřené vyrobeno typy jako parametry, návratové typy nebo lokální proměnné.

skef48fy.collapse_all(cs-cz,VS.110).gifObecné metody tříd obecný

Obecný tříd, které mají parametry žádné další typ metody jsou obvykle označovány jako obecné Ačkoli jsou implicitně parametrizovanou ohraničujícím obecná třída.

signatura než -obecná metoda může zahrnovat jeden nebo více parametrů typu ohraničující třída, buď přímo, nebo otevřený konstruovány typu.Příklad:

void MyMethod(MyClass<ItemType> x) {}

Subjekt těchto metod můžete také použít tyto parametry typu.

Obecné metody tříd obecný

Je možné deklarovat obecné metody tříd obecný a obecné.Příklad:

Použití vnořených typů tříd Obecné

Stejně jako pomocí běžných tříd můžete deklarovat jiných typů uvnitř obecná třída.Vnořené třída prohlášení implicitně parametrizovanou parametry typu prohlášení vnější třída .Tedy odlišné vnořené třída je definována pro každý typ konstrukce vnější.Například v prohlášení,

// generic_classes_5.cpp
// compile with: /clr /c
generic <typename ItemType>
ref struct Outer {
   ref class Inner {};
};

Typ vnější <int>:: vnitřní není stejný jako typ vnější <double>:: vnitřní.

Jako obecné metody obecný tříd typu další parametry lze definovat pro vnořený typ.Pokud používáte stejné názvy parametr typu třídavnitřní a vnější, vnitřní typu parametr bude skrýt vnější typ parametr.

// 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
   };
};

Protože neexistuje žádný způsob, jak odkazovat na vnější typ parametr, kompilátor ohlásí upozornění v této situaci.

Když vyrobeno vnořené obecné typy jsou pojmenovány, parametr typu vnějšího typu zahrnut v seznamu typ parametr typu vnitřní přestože vnitřní typ implicitně parametrizovanou typu vnějšího typu parametr.Ve výše uvedeném případě by název typu vyrobeno vnější <int>:: vnitřní <string>.

Následující příklad znázorňuje vytváření a čtení vnořené typy pomocí tříd obecné propojeného seznamu.

Vlastnosti, události, indexování a operátorů tříd obecný

  • Vlastnosti, události, indexování a operátory můžete použít parametry typu generic ohraničující třída jako vrácené hodnoty, parametry nebo lokální proměnné, např. při ItemType je parametr typu třída:

    public ItemType MyProperty {}
    
  • Vlastnosti, události, indexování a hospodářské subjekty nemohou samy o sobě být parametrické.

Obecný struktur

Pravidla pro deklarování a pomocí obecného struktur jsou stejné jako u generické třídy, s výjimkou pro rozdíly v jazyce Visual C++ odkazovat sena vědomí v.

Viz také

Další zdroje

Obecné typy (rozšíření komponent C++)