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

Template và hướng đối tượng

39 739 0
Tài liệu đã được kiểm tra trùng lặp

Đ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

Định dạng
Số trang 39
Dung lượng 83,67 KB

Nội dung

Bài giảng kỹ thuật lập trình Thầy Cường Học viên bưu chính viễn thông TP HCM

Trang 1

• Từ khoá extern và asm

• Hàm chuyển kiểu

• Những khác biệt giữa C và C++

Trang 3

I/ Hàm template

Hàm template (hàm mẫu) định nghiã một dãy tổng quát các tác vụ được dùng cho nhiều kiểu dữ liệu khác nhau Trong đó, kiểu dữ liệu được dùng sẽ được truyền đến hàm dưới dạng một tham số

Với cơ chế này, một thủ tục có thể được dùng cho nhiều kiểu dữ liệu khác nhau

Trong môn học Cấu trúc dữ liệu và thuật toán, nhiều giải thuật giống nhau về mặt luận lý, bất kể nó làm việc với kiểu dữ liệu gì Ví dụ giải thuật QuickSort là giống nhau, không cần biết nó sẽ áp dụng cho dãy số nguyên hay dãy số thực Vấn đề là ở chỗ dữ liệu được xử lý khác nhau

Bằng cách tạo ra hàm template, có thể định nghiã bản chất của giải thuật độc lập với kiểu dữ liệu mà nó xử lý Dựa vào hàm template, trình biên dịch sẽ tự động sinh ra mã chương trình để dùng cho một kiểu dữ liệu cụ thể nào đó khi thực thi chương

trình Thực chất là việc tạo ra một hàm template đồng nghiã với việc tạo ra một hàm mà nó có thể tự quá tải lên chính nó

Khai báo hàm template

template < class Ttype > ret_type func_name(parameter list)

{

// body of function }

Từ khoá template dùng để tạo ra một dạng mẫu mô tả hoạt động của hàm và

nhường cho trình biên dịch điền vào một cách chi tiết khi cần

Ttype là tên hình thức cho kiểu dữ liệu được dùng bên trong hàm, nó sẽ được thay thế bởi một kiểu dữ liệu cụ thể khi trình biên dịch sinh ra một phiên bản chi tiết của hàm

Quá trình tạo ra phiên bản chi tiết của hàm được gọi là quá trình sinh hàm Việc tạo

ra

bản chi tiết của hàm template được gọi là tạo ra ngay tức khắc (instantiating) một hàm Nói một cách khác là một hàm sinh ra phiên bản dùng trong chốc lát của hàm template

Trang 4

Ví dụ 1.1 Hàm template trao đổi nội dung của hai biến

// Function template example

#include <iostream.h>

// This is a function template

template <class X> void swapargs(X &a, X &b)

cout << "Original i, j: " << i << ' ' << j << endl;

cout << "Original x, y: " << x << ' ' << y << endl;

swapargs(i, j); // swap integers

swapargs(x, y); // swap floats

cout << "Swapped i, j: " << i << ' ' << j << endl;

cout << "Swapped x, y: " << x << ' ' << y << endl;

return 0;

}

template <class X> void swapargs(X &a, X &b)

Dòng này thông báo với chương trình hai vấn đề :

- Đây là một hàm template

- Đây là điểm bắt đầu của phần định nghiã một hàm template

X có ý nghiã là kiểu dữ liệu của các biến cần trao đổi nội dung

Trang 5

Hàm swapargs() được gọi hai lần trong hàm main() : một lần để trao đổi nội dung hai biến kiểu số nguyên, và lần sau cho hai biến kiểu số thực Do hàm swapargs() là

một hàm template, cho nên trình biên dịch sẽ tự động phát sinh ra hai phiên bản của

hàm swapargs() tương ứng với kiểu dữ liệu của đối số thực gởi vào

• Phần khai báo template của một hàm mẫu không bắt buộc phải viết trên cùng một dòng với tên hàm

void swapargs(X &a, X &b)

Trang 6

Trong hàm template, có thể sử dụng nhiều kiểu dữ liệu khác nhau bằng cách

đưa vào một danh sách các kiểu dữ liệu dùng trong hàm, trong đó tên hình thức của các kiểu được phân cách nhau bằng dấu phẩy

#include <iostream.h>

template <class type1, class type2>

void myfunc(type1 x, type2 y)

Trang 7

// Overriding a template function

// This overrides the generic version of swapargs()

void swapargs(int a, int b)

cout << "Original i, j: " << i << ' ' << j << endl;

cout << "Original x, y: " << x << ' ' << y << endl;

Trang 8

swapargs(i, j); // this calls the explicitly overloaded swapargs()

swapargs(x, y); // swap floats

cout << "Swapped i, j: " << i << ' ' << j << endl;

cout << "Swapped x, y: " << x << ' ' << y << endl;

return 0;

}

@ Việc quá tải lên một hàm template, cho phép lập trình viên thay đổi giải thuật của một phiên bản của hàm template để phù hợp với một tình huống đặc biệt Tuy nhiên, nếu muốn sử dụng những phiên bản hoàn toàn khác nhau của một hàm trong đó có nhiều kiểu dữ liệu, hãy dùng quá tải hàm thay vì hàm template

int bubblesort (X a[], int n);

với n xác định số lượng các phần tử của dãy a

3 Viết một chương trình, trong đó có hàm template tên là find(), thực hiện việc tìm kiếm một đối tượng trên một dãy Nếu tìm thấy, hàm trả về chỉ số của đối tượng tìm được, ngược lại hàm sẽ trả về trị là -1 Hàm có dạng

int find(int object, int *list, int size);

với size xác định số lượng các phần tử của dãy

Trang 9

II/ Lớp template

Lớp template định nghiã tất cả các thuật toán được dùng bởi lớp đó, tuy nhiên kiểu dữ liệu thực sự mà lớp này xử lý sẽ được định rõ dưới dạng tham số lúc tạo ra các đối tượng thuộc lớp template đó

• Khai báo

template < class Ttype > class class_name {

// body of class };

Ttype là tên lớp hình thức và nó sẽ được xác định khi tạo ra một lớp Khi cần thiết, có thể định nghiã lớp template với nhiều kiểu dữ liệu template bằng cách dùng một danh sách các tên kiểu hình thức được phân cách nhau bằng dấu phẩy

• Sau khi tạo ra lớp template, có thể sinh ra một lớp cụ thể từ lớp template

class_name < type > object_name;

với type là tên thực của kiểu dữ liệu mà lớp đó xử lý

Các hàm thành phần của một lớp template cũng là các hàm template một cách tự động và không cần phải dùng từ khoá template để khai báo tường minh cho các hàm đó

Ví dụ 2.1 Tạo ra lớp template cho một danh sách liên kết, dùng để lưu các ký tự // A simple generic linked list

Trang 10

next = 0;

}

list *getnext() { return next; }

data_t getdata() { return data; }

for(i=1; i<26; i++) {

p = new list<char> ('a' + i);

Trang 11

@ Lưu ý dòng lệnh

list<char> start('a') ;

với kiểu dữ liệu được truyền sang cho lớp xuất hiện bên trong cặp dấu

ngoặc < >

Kết quả chương trình ?

@ Có thể dùng danh sách list để lưu trữ các phần tử kiểu số nguyên hay không ?

• Có thể sử dụng lớp template list ở trên cho một kiểu dữ liệu mới do người dùng định nghiã Ví dụ, về một cấu trúc lưu thông tin về danh bạ điện thoại

với structvar là biến có kiểu dữ liệu là addr

• Các hàm template và lớp template là một công cụ mạnh làm gia tăng hiệu quả

lập trình, bởi vì nó cho phép định nghiã một giải thuật ở dạng tổng quát và sử dụng được cho nhiều loại dữ liệu có kiểu khác nhau Ngoài ra, còn tiết kiệm được thời gian gõ chương trình vào máy tính, do không phải gõ lại nhiều đoạn mã chương trình giống nhau về mặt giải thuật nhưng khác nhau về kiểu dữ liệu mà nó xử lý

Ví dụ 2.2 Tạo ra lớp template cho stack, dùng để lưu các kiểu dữ liệu ký tự và

kiểu double

// This function demonstrates a generic stack

Trang 12

#include <iostream.h>

#define SIZE 10

// Create a generic stack class

template <class StackType > class stack {

StackType stck[SIZE]; // holds the stack

public:

void init() { tos = 0; } // initialize stack

void push(StackType ch); // push object on stack

StackType pop(); // pop object from stack

cout << "Stack is empty.\n";

return 0; // return null on empty stack

}

tos ;

return stck[tos];

}

Trang 13

int main()

{

// Demonstrate character stacks

stack<char> s1, s2; // create two stacks

for(i=0; i<3; i++) cout << "Pop s1: " << s1.pop() << "\n";

for(i=0; i<3; i++) cout << "Pop s2: " << s2.pop() << "\n";

// demonstrate double stacks

stack<double> ds1, ds2; // create two stacks

// initialize the stacks

for(i=0; i<3; i++) cout << "Pop ds1: " << ds1.pop() << "\n";

for(i=0; i<3; i++) cout << "Pop ds2: " << ds2.pop() << "\n";

Trang 14

return 0;

}

Kết quả chương trình ?

Một lớp template có thể chứa nhiều kiểu dữ liệu tổng quát ( generic data types)

Khi đó các tên kiểu dữ liệu template được khai báo trong phần template dưới dạng một danh sách và phân cách nhau bằng dấu phẩy

Ví dụ 2.3 Một lớp có hai kiểu dữ liệu tổng quát

// This example uses two generic data types in a class definition

myclass<int, double> ob1(10, 0.23); // a/

myclass<char, char *> ob2('X', "This is a test"); // b/

ob1.show(); // show int, double

ob2.show(); // show char, char *

Trang 15

@ Trong cả hai trường hợp ở trên (a/, b/) , trình biên dịch sẽ tự động sinh ra các dữ liệu và hàm tương ứng với mệnh đề tạo ra lớp

Bài tập II

1 Viết chương trình tạo và biểu diễn một lớp template lưu trữ queue

2 Viết chương trình tạo một lớp template với tên input, khi hàm tạo của lớp này được gọi nó sẽ thực hiện các công việc sau :

- thông báo nhắc người dùng nhập dữ liệu : prompt message

- nhận dữ liệu từ bàn phím

- thông báo lỗi nếu dữ liệu không nằm trong vùng trị cho phép

giữa min_value và max_value

Đối tượng thuộc kiểu input được khai báo như sau

input ob("prompt message", min_value, max_value) ;

III/ Điều khiển ngoại lệ (exception handling)

C++ (theo chuẩn ANSI C++, 1994) cung cấp sẵn một cơ chế xử lý lỗi gọi là điều

khiển ngoại lệ Qua đó có thể khống chế và đáp ứng lại các lỗi xuất hiện lúc thực thi chương trình

1/ Điều khiển ngoại lệ của C++ gồm ba từ khoá : try, catch, throw

Một cách tổng quát, các mệnh đề dùng để giám sát các ngoại lệ được đặt bên trong

một khối try Khi một ngoại lệ (tức một lỗi) xuất hiện bên trong khối try, nó sẽ được ném ra (bằng từ khoá throw) Tiếp theo ngoại lệ này sẽ bị bắt lại để xử lý (bằng từ khoá catch)

Bất kỳ một mệnh đề nào thực hiện việc ném ra ngoài một ngoại lệ phải đặt ở bên trong khối try (hoặc bên trong một hàm được gọi đến từ một mệnh đề bên trong khối

try) Tất cả các ngoại lệ phải bị bắt lại bởi một mệnh đề catch đặt ngay sau khối try mà từ đó nó được ném ra

Trang 16

Dạng khai báo tổng quát

try {

// try block

throw exception ; }

catch (type1 arg ) {

// catch block }

catch (type2 arg ) {

// catch block }

catch (typeN arg ) {

// catch block }

exception là giá trị được ném ra

type1, type2, , typeN kiểu dữ liệu của các đối số

Kiểu dữ liệu của ngoại lệ chính là cơ sở để quyết định xem ngoại lệ đó được xử lý bằng mệnh đề catch nào Nghiã là nếu kiểu dữ liệu xác định trong một catch nào đó trùng hợp với kiểu dữ liệu của ngoại lệ, thì mệnh đề catch đó được thực thi Tất cả các mệnh đề catch khác sẽ bị bỏ qua

Khi một ngoại lệ bị bắt lại, arg sẽ nhận giá trị của ngoại lệ này Giá trị ngoại lệ có thể là một kiểu dữ liệu bất kỳ, kể cả kiểu dữ liệu mới do người dùng tạo ra

Ví dụ 3.1 Cách điều khiển ngoại lệ của C++

// A simple exception handling example

#include <iostream.h>

int main()

{

cout << "start\n";

Trang 17

try { // start a try block

cout << "Inside try block\n";

throw 10; // throw an error

cout << "This will not execute"; // not execution

}

catch (int i) { // catch an error

cout << "Caught One! Number is: ";

Inside try block

Caught One ! Numbers is : 10

Kiểu của ngoại lệ phải giống với kiểu xác định trong mệnh đề catch

Ví dụ 3.2 Một chương trình kết thúc không bình thường do mệnh đề catch sẽ không bắt được ngoại lệ ném ra

// This example will not work

#include <iostream.h>

int main()

{

Trang 18

cout << "start\n";

cout << "Inside try block\n";

throw 10; // throw an error

cout << "This will not execute";

}

catch (double i) { // Won't work for an int exception

cout << "Caught One! Number is: ";

inside try block

Abnormal program terminal

(Dạng thông báo lỗi này có thể khác nhau tuỳ thuộc vào mỗi compiler)

Một ngoại lệ có thể được ném ra từ một mệnh đề nằm ngoài khối try chỉ khi nó được đặt trong một hàm, mà hàm này được gọi từ trong khối try

Ví dụ 3.3 Một chương trình kết thúc bình thường

// Throwing an exception from a function outside the try block

#include <iostream.h>

void Xtest(int test)

{

cout << "Inside Xtest, test is: " << test << "\n";

if(test) throw test;

}

Trang 19

int main()

{

cout << "start\n";

cout << "Inside try block\n";

Xtest(0);

Xtest(1);

Xtest(2);

}

catch (int i) { // catch an error

cout << "Caught One! Number is: ";

Inside try block

Inside Xtest, test is: 0

Inside Xtest, test is: 1

Caught One! Number is: 1

end

Một khối try có thể thuộc về một hàm khác hàm main() của chương trình Trong trường hợp này, cứ mỗi lần thực hiện hàm, bộ điều khiển ngoại lệ của hàm đó sẽ được lặp lại

Ví dụ 3.4 Một khối try/catch có thể ở bên trong một hàm khác hàm main()

#include <iostream.h>

// A try/catch can be inside a function other than main()

void Xhandler(int test)

{

try{

Trang 20

if(test) throw test;

Có thể tạo nhiều mệnh đề catch cho mỗi khối try Do mỗi mệnh đề catch có thể

bắt một kiểu ngoại lệ khác biệt với kiểu ở các catch khác

Ví dụ 3.5 Mỗi biểu thức catch được kiểm tra theo thứ tự xuất hiện và chỉ có một mệnh đề trùng kiểu mới được thực thi Tất cả các mệnh đề còn lại đều bị bỏ qua

#include <iostream.h>

// Different types of exceptions can be caught

void Xhandler(int test)

{

try{

if(test) throw test;

else throw "Value is zero";

Giải thích kết quả chương trình ?

start Caught One! Ex #: 1 Caught One! Ex #: 2 Caught One! Ex #: 3 end

Trang 21

Dấu " " bắt được tất cả kiểu

• Khi một hàm được gọi từ bên trong khối block, có thể hạn chế kiểu dữ liệu nào của ngoại lệ mà hàm có thể ném được Để thực hiện các hạn chế, cần phải throw vào định nghiã hàm Dạng tổng quát

ret_type func_name(arg_list) throw(type_list) {

}

Giải thích kết quả chương trình ?

start Caught One! Ex #: 1 Caught One! Ex #: 2 Caught a string: Value is zero Caught One! Ex #: 3

end

Trang 22

Chỉ có các ngoại lệ có kiểu trong danh sách type_list (phân cách bằng dâú phẩy) là

được ném ra từ hàm Ngược lại, việc ném ra các ngoại lệ thuộc kiểu khác là chương trình kết thúc bất thường

Lưu ý

Nếu đang dùng trình biên dịch tuân theo chuẩn ANSI C++, thì việc thử ném

ra một ngoại lệ mà không có mệnh đề catch nào bắt được sẽ làm gọi hàm

unexpected() Theo mặc định, hàm unexpected() sẽ gọi tiếp hàm abort() để

làm kết thúc chương trình một cách bất thường

Cũng có thể định lại để hàm unexpected() gọi đến một hàm xử lý kết thúc khác nếu

lập trình viên muốn Xem chi tiết tài liệu hướng dẫn di kèm trong trình biên dịch

• Nếu muốn ném một lần nữa một ngoại lệ từ bên trong bộ đều khiển ngoại lệ, hãy gọi một lần nữa từ khoá throw không cần kèm theo giá trị của ngoại lệ Cách này cho phép ngoại lệ hiện hành được truyền đến một đoạn try/catch khác

Ví dụ 3.6 Dùng catch( ) để bắt mọi ngoại lệ

// This example catches all exceptions

#include <iostream.h>

void Xhandler(int test)

{

try{

if(test==0) throw test; // throw int

if(test==1) throw 'a'; // throw char

if(test==2) throw 123.23; // throw double

}

catch( ) { // catch all exceptions

cout << "Caught One!\n";

}

}

int main()

{

Ngày đăng: 21/08/2012, 15:40

TỪ KHÓA LIÊN QUAN

TRÍCH ĐOẠN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w