close up photo of programming of codes

codecungnhau.com

Một trang web về kỹ thuật lập trình

C++ Templates: khuôn mẫu lớp

Hàm thành viên của khuôn mẫu lớp

Các hàm thành viên có thể được định nghĩa bên trong hoặc bên ngoài một khuôn mẫu lớp. Chúng được định nghĩa giống như các khuôn mẫu hàm nếu được định nghĩa bên ngoài khuôn mẫu lớp.

// member_function_templates1.cpp
template<class T, int i> class MyStack
{
    T*  pStack;
    T StackBuffer[i];
    static const int cItems = i * sizeof(T);
public:
    MyStack( void );
    void push( const T item );
    T& pop( void );
};
template< class T, int i > MyStack< T, i >::MyStack( void )
{
};
template< class T, int i > void MyStack< T, i >::push( const T item )
{
};
template< class T, int i > T& MyStack< T, i >::pop( void )
{
};
int main()
{
}

Lưu ý rằng giống như với bất kỳ hàm thành viên của khuôn mẫu lớp nào, việc định nghĩa của hàm thành viên hàm tạo của lớp bao gồm danh sách đối số mẫu hai lần.

Các hàm thành viên có thể là các khuôn mẫu hàm, chỉ định các tham số bổ sung, như trong ví dụ sau,

// member_templates.cpp
template<typename T>
class X
{
public:
   template<typename U>
   void mf(const U &u);
};
template<typename T> template <typename U>
void X<T>::mf(const U &u)
{
}
int main()
{
}

Khuôn mẫu lớp lồng nhau

Các mẫu có thể được định nghĩa trong các lớp hoặc các khuôn mẫu lớp, trong trường hợp đó chúng được gọi là các khuôn mẫu thành viên. Các khuôn mẫu thành viên là các lớp được gọi là các mẫu lớp lồng nhau. Các khuôn mẫu thành viên là các hàm được thảo luận trong các bài viết sau. Các khuôn mẫu lớp lồng nhau được khai báo là các khuôn mẫu lớp bên trong phạm vi của lớp bao nó. Chúng có thể được định nghĩa bên trong hoặc bên ngoài lớp. Đoạn chương trình sau minh họa một khuôn mẫu lớp lồng trong một lớp bình thường.

// nested_class_template1.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class X
{
   template <class T>
   struct Y
   {
      T m_t;
      Y(T t): m_t(t) { }
   };
   Y<int> yInt;
   Y<char> yChar;
public:
   X(int i, char c) : yInt(i), yChar(c) { }
   void print()
   {
      cout << yInt.m_t << " " << yChar.m_t << endl;
   }
};
int main()
{
   X x(1, 'a');
   x.print();
}
// nested_class_template2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
template <class T>
class X
{
   template <class U> class Y
   {
      U* u;
   public:
      Y();
      U& Value();
      void print();
      ~Y();
   };
   Y<int> y;
public:
   X(T t) { y.Value() = t; }
   void print() { y.print(); }
};
template <class T>
template <class U>
X<T>::Y<U>::Y()
{
   cout << "X<T>::Y<U>::Y()" << endl;
   u = new U();
}
template <class T>
template <class U>
U& X<T>::Y<U>::Value()
{
   return *u;
}
template <class T>
template <class U>
void X<T>::Y<U>::print()
{
   cout << this->Value() << endl;
}
template <class T>
template <class U>
X<T>::Y<U>::~Y()
{
   cout << "X<T>::Y<U>::~Y()" << endl;
   delete u;
}
int main()
{
   X<int>* xi = new X<int>(10);
   X<char>* xc = new X<char>('c');
   xi->print();
   xc->print();
   delete xi;
   delete xc;
}
//Output:
X<T>::Y<U>::Y()
X<T>::Y<U>::Y()
10
99
X<T>::Y<U>::~Y()
X<T>::Y<U>::~Y()

Các lớp cục bộ không được phép có các khuôn mẫu thành viên.

Khuôn mẫu friends

Khuôn mẫu lớp có thể có “bạn bè”. Một lớp hoặc khuôn mẫu lớp, hàm hoặc khuôn mẫu hàm có thể là bạn với một khuôn mẫu lớp. Các đặc biệt hóa của khuôn mẫu lớp hoặc khuôn mẫu hàm, nhưng không phải là đặc biệt hóa một phần cũng có thể là bạn với khuôn mẫu lớp. Trong ví dụ sau, một hàm bạn được định nghĩa là một khuôn mẫu hàm trong khuôn mẫu lớp. Chương trình này tạo ra một phiên bản của hàm bạn cho mỗi lần khởi tạo mẫu. Cấu trúc này rất hữu ích nếu hàm bạn phụ thuộc vào các tham số mẫu giống như lớp.

// template_friend1.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
template <class T> class Array {
   T* array;
   int size;
public:
   Array(int sz): size(sz) {
      array = new T[size];
      memset(array, 0, size * sizeof(T));
   }
   Array(const Array& a) {
      size = a.size;
      array = new T[size];
      memcpy_s(array, a.array, sizeof(T));
   }
   T& operator[](int i) {
      return *(array + i);
   }
   int Length() { return size; }
   void print() {
      for (int i = 0; i < size; i++)
         cout << *(array + i) << " ";
      cout << endl;
   }
   template<class T>
   friend Array<T>* combine(Array<T>& a1, Array<T>& a2);
};
template<class T>
Array<T>* combine(Array<T>& a1, Array<T>& a2) {
   Array<T>* a = new Array<T>(a1.size + a2.size);
   for (int i = 0; i < a1.size; i++)
      (*a)[i] = *(a1.array + i);
   for (int i = 0; i < a2.size; i++)
      (*a)[i + a1.size] = *(a2.array + i);
   return a;
}
int main() {
   Array<char> alpha1(26);
   for (int i = 0 ; i < alpha1.Length() ; i++)
      alpha1[i] = 'A' + i;
   alpha1.print();
   Array<char> alpha2(26);
   for (int i = 0 ; i < alpha2.Length() ; i++)
      alpha2[i] = 'a' + i;
   alpha2.print();
   Array<char>*alpha3 = combine(alpha1, alpha2);
   alpha3->print();
   delete alpha3;
}
//Output:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z

Ví dụ tiếp theo liên quan đến đặc biệt hóa khuôn mẫu. Khuôn mẫu hàm đặc biệt sẽ tự động là bạn nếu khuôn mẫu hàm ban đầu cũng là bạn. Cũng có thể khai báo chỉ phiên bản đặc biệt của khuôn mẫu là bạn. Để làm điều này, bạn phải đặt định nghĩa của khuôn mẫu bạn đặc biệt này bên ngoài khuôn mẫu lớp.

// template_friend2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
template <class T>
class Array;
template <class T>
void f(Array<T>& a);
template <class T> class Array
{
    T* array;
    int size;
public:
    Array(int sz): size(sz)
    {
        array = new T[size];
        memset(array, 0, size * sizeof(T));
    }
    Array(const Array& a)
    {
        size = a.size;
        array = new T[size];
        memcpy_s(array, a.array, sizeof(T));
    }
    T& operator[](int i)
    {
        return *(array + i);
    }
    int Length()
    {
        return size;
    }
    void print()
    {
        for (int i = 0; i < size; i++)
        {
            cout << *(array + i) << " ";
        }
        cout << endl;
    }
    // If you replace the friend declaration with the int-specific
    // version, only the int specialization will be a friend.
    // The code in the generic f will fail
    // with C2248: 'Array<T>::size' :
    // cannot access private member declared in class 'Array<T>'.
    //friend void f<int>(Array<int>& a);
    friend void f<>(Array<T>& a);
};
// f function template, friend of Array<T>
template <class T>
void f(Array<T>& a)
{
    cout << a.size << " generic" << endl;
}
// Specialization of f for int arrays
// will be a friend because the template f is a friend.
template<> void f(Array<int>& a)
{
    cout << a.size << " int" << endl;
}
int main()
{
    Array<char> ac(10);
    f(ac);
    Array<int> a(10);
    f(a);
}
//Output:
10 generic
10 int

Ví dụ tiếp theo cho thấy một khuôn mẫu lớp bạn được khai báo trong một khuôn mẫu lớp. Khuôn mẫu lớp sau đó được sử dụng làm đối số mẫu cho lớp bạn. Các khuôn mẫu lớp bạn phải được định nghĩa bên ngoài khuôn mẫu lớp mà chúng được khai báo. Bất kỳ sự đặc biệt hóa toàn phần hoặc một phần nào của khuôn mẫu bạn cũng là bạn của khuôn mẫu lớp gốc.

// template_friend3.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

template <class T>
class X
{
private:
   T* data;
   void InitData(int seed) { data = new T(seed); }
public:
   void print() { cout << *data << endl; }
   template <class U> friend class Factory;
};

template <class U>
class Factory
{
public:
   U* GetNewObject(int seed)
   {
      U* pu = new U;
      pu->InitData(seed);
      return pu;
   }
};

int main()
{
   Factory< X<int> > XintFactory;
   X<int>* x1 = XintFactory.GetNewObject(65);
   X<int>* x2 = XintFactory.GetNewObject(97);

   Factory< X<char> > XcharFactory;
   X<char>* x3 = XcharFactory.GetNewObject(65);
   X<char>* x4 = XcharFactory.GetNewObject(97);
   x1->print();
   x2->print();
   x3->print();
   x4->print();
}
//Output:
//65
//97
//A
//a

Đã đăng vào

trong

,

bởi

Bình luận

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *