1. Trang chủ
  2. » Công Nghệ Thông Tin

Kỹ thuật lập trình C/C++-Chương:Lập trình khái quát với hàm ppt

19 376 3

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Lập trình khái quát với hàm
Tác giả Đào Trung Kiên
Trường học Đại học Bách khoa Hà Nội
Chuyên ngành Kỹ thuật lập trình
Thể loại bài giảng
Năm xuất bản 2011/2012
Thành phố Hà Nội
Định dạng
Số trang 19
Dung lượng 223 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Khái niệm Đôi khi ta muốn viết một lần nhưng có thể tạo ra các hàm với tham số thuộc nhiều kiểu khác nhau , thay vì phải viết chồng nhiều hàm tương tự nhau  int maxint a, int b { retur

Trang 1

Lập trình khái quát với hàm

(function templates)

Trang 2

Khái niệm

 Đôi khi ta muốn viết một lần nhưng có thể tạo ra các hàm với tham số thuộc nhiều kiểu khác nhau , thay vì phải viết chồng nhiều hàm tương tự nhau

 int max(int a, int b) { return a>b ? b:a; }

double max(double a, double b) { return a>b ? b:a; }

float max(float a, float b) { return a>b ? b:a; }

 lập trình ở mức độ khái quát cao hơn: coi kiểu của biến cũng là tham số (type parameterization)

 Khuôn mẫu hàm (function template): là khái niệm giúp

định nghĩa những hàm mà chưa xác định kiểu của các tham số

 Có thể hiểu là viết gộp chung các hàm chồng giống nhau về mặt thuật toán

 Kiểu của các tham số là tham số của khuôn mẫu

Trang 3

Định nghĩa hàm khái quát

 Ví dụ 1:

 template <class T>

void swap(T& a, T& b) {

 T được giả định là kiểu của các tham số a, b và biến c

 T sẽ được xác định khi gọi hàm

 T là tham số của khuôn mẫu, trong khi a, b là tham số của hàm

 Ví dụ 2:

 template <class Containter, class Object>

void push(Containter& s, Object o) { }

 Có thể dùng từ khoá “typename” thay vì “class”

 template <typename T>

void swap(T& a, T& b) { }

Trang 4

Gọi hàm khái quát

 Gọi với kiểu tường minh:

 max<int>(a, b);

max<double>(x, y);

swap<String&>(s1, s2);

swap<Worker*&>(p1, p2);

push<List&, Student>(l, st);

 Gọi với kiểu ngầm định:

double x, y;

max(a, b); //  max<int>(a, b);

max(x, y); //  max<double>(x, y);

max(a, x); //  lỗi

Trang 5

Chồng hàm khái quát

 Các khuôn mẫu hàm cũng có thể được định nghĩa chồng

 template <class T> T max(T a, T b) { }

template <class T> T max(T a, T b, T c) { } template <class T> T max(T* arr, int n) { }

 Gọi hàm chồng

 max<int>(10, 20);

max('c', 'f');

max<double>(1.5, 2.1, 3.14);

max("1un34k", 6);

Trang 6

Cá biệt hoá hàm khái quát

 Có thể định nghĩa các phiên bản cho trường hợp riêng của một hàm khái quát

 template<class T> T max(T a, T b) {

return a>b ? b:a; }

template<> std::string

max(std::string s1, std::string s2) {

return s1.compare(s2) == 1 ? s1:s2; }

 Cá biệt hoá không hoàn toàn

 template <class Containter, class Object>

void push(Containter& s, Object o) { }

template <class Object>

void push(Stack& s, Object o) { }

Trang 7

Không chỉ khái quát hoá kiểu của tham số…

 Khái quát hoá kiểu trả về

 template <class Worker, class Product>

Product makeProd(Worker& w) {

w.work();

return w.getResult();

}

 Khái quát hoá kiểu của biến cục bộ

 template <class List, class Iterator>

void forEach(const List& l) {

Iterator i = l.first();

for (; i!=l.last(); i = i.next())

doSmth(i.get());

}

Trang 8

Tham số của khuôn mẫu không chỉ là kiểu

 Có thể là các giá trị  sử dụng giá trị đó như hằng

 template<class Object, int N>

Object* makeArray() {

string* p1 = makeArray<string, 5>();

SinhVien* p2 = makeArray<SinhVien, 10>();

 Cả giá trị và kiểu cùng là tham số

 template<class T, T min, T max>

T range(T t) {

return t<min ? min :

(t>max ? max : t);

}

y = range<double, -1.5, 2.> (x);

b = range<int, 10, 20> (a);

Trang 9

Lưu ý khi dùng các hàm khái quát

 Phần thực thi của các khuôn mẫu hàm chỉ thực sự được biên dịch khi có thông tin về kiểu

 nếu viết khuôn mẫu hàm trong thư viện thì cả nguyên mẫu và

phần thực thi của hàm đều viết trong file h

(có thể viết riêng phần thực thi ra một file khác rồi include vào file h)

 Khi sử dụng tham số thuộc kiểu gì thì trình biên dịch mới sinh ra hàm tương ứng với kiểu tham số đó

 int a = 10, b = 20;

swap(a, b); //  sinh ra: void swap(int&, int&) { }

swap<float>(x, y); //  void swap(float&, float&) { }

 Có thể khi dùng ở trường hợp cụ thể mới phát sinh lỗi cú pháp

 template <class T> T divide(T a, T b)

{ return a/b; } double z = divide(1.5, 0.5); // OK

const char* c = divide("ssss", "dddd"); // lỗi

Trang 10

Lập trình khái quát với lớp

(class templates)

Trang 11

Khái niệm

 Tương tự với hàm, các lớp cũng có thể được khái quát hoá  khuôn mẫu lớp

 Lớp được khai báo sử dụng những kiểu chưa xác định

và được tham số hoá

 template<class Object>

class Array {

private:

int N;

Object* p;

public:

Object& operator[](int i) { }

Trang 12

Phương thức bên ngoài khuôn mẫu lớp

template<class Object>

class Array {

private:

int N;

Object* p;

public:

Array(int N);

~Array();

void setAt(int i, Object o);

int length() const;

Object& operator[](int i);

};

template<class Object>

Array <Object> ::Array(int N) {

this->N = N;

p = new Object[N]; }

template<class Object>

Array <Object> ::~Array() { delete[] p; }

template<class Object>

void Array <Object> ::

setAt(int i, Object o) { p[i] = o; }

template<class Object>

int Array <Object> ::length() const { return N; }

template<class Object>

Object& Array <Object> ::

operator[](int i) { return p[i]; }

 Các phương thức ở ngoài được khai báo tương tự như các khuôn mẫu hàm

Trang 13

Sử dụng đối tượng của lớp khái quát

 Ví dụ:

 Array<double> a(10);

for (int i=0; i<10; i++)

a.setAt(i, i*2);

typedef Array<string> StrArray;

StrArray s(2);

s[0] = string("abcd");

s[1] = string("12345");

 Kết hợp khuôn mẫu lớp và hàm

 template< class Object >

void printArray( Array<Object> &a) {

for (int i=0; i<a.length(); i++)

cout << a[i];

}

printArray(a);

printArray(s);

Trang 14

Hàm bạn và lớp bạn

 Bạn riêng của từng lớp tương ứng

 template<class T>

class Array {

friend void sort(Array<T>& a);

friend class Serializer<T>;

};

 Bạn chung của tất cả các lớp

 template<class T>

class A {

friend void func1();

template<class X> friend int func2();

friend class B;

};

Trang 15

Cá biệt hoá lớp khái quát

 template<class Key, class Data> class Map {

Data find(Key k);

};

// cá biệt hoá hoàn toàn

template<> class Map<int, int> {

int find(int k);

};

// cá biệt hoá không hoàn toàn

template<class Data> class Map<int, Data> {

Data find(int k);

};

Trang 16

Giá trị mặc định của tham số khuôn mẫu

 Các tham số của khuôn mẫu lớp có thể có giá trị mặc

định

 template<class Object = int, int N = 100>

class Pool {

};

Pool p1; //  Pool<int, 100> p1;

Pool<string> p2; //  Pool<string, 100> p2

Pool<double, 20> p3;

 Chú ý: chỉ khuôn mẫu lớp mới có giá trị mặc định của

tham số, khuôn mẫu hàm không có

Trang 17

Biến static của lớp khái quát

 Mỗi lớp được sinh ra từ khuôn mẫu có biến static riêng

 template<class Data>

class smartptr {

static smartptr<Data> nullptr;

};

template<class Data>

static smartptr<Data> smartptr<Data>::nullptr;

smartptr<string> p1 = smartptr<string>::nullptr; smartptr<double> p2 = smartptr<double>::nullptr;

 Tương tự với các phương thức static

Trang 18

Các lớp khái quát liên quan

 template<class T> class Iterator;

template< class T > class List {

Iterator<T> begin() { } Iterator<T> end() { } };

template<T> class Iterator {

T& getData() { } Iterator<T> next() { } };

List<float> l;

Iterator<float> i;

for (i = l.begin(); i != l.end(); i = i.next())

cout << i.getData() << endl;

Trang 19

Bài tập

1. Viết hàm nhập dữ liệu cho mảng có kiểu bất kỳ

2. Viết hàm sắp xếp một mảng bất kỳ theo 2 cách: (C) sử dụng một

hàm so sánh làm cơ sở cho thứ tự sắp xếp, (C++) dùng template

void sortC(void* a, int n, int size,

int (*compare)(void*, void*));

template<class T> void sortCpp(T* a, int n);

3. Viết lớp Stack cho phép chứa dữ liệu kiểu bất kỳ mà không cần

dùng con trỏ void*

4. Sửa lại lớp DSLK cho phép chứa dữ liệu kiểu bất kỳ

5. Sửa lại lớp Iterator cho DSLK ở trên

6. Sửa lớp Vector cho phép làm việc với cả dữ liệu float và double

7. Sửa lớp String cho phép làm việc với cả chuỗi ASCII (char) và

Unicode (wchar_t)

Ngày đăng: 23/03/2014, 08:21

TỪ KHÓA LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm

w