25/05/2018, 14:45

Đối của phương thức, con trỏ this

Chúng ta hãy xem lại phương thức nhapsl của lớp DIEM void DIEM::nhapsl() { cout <<" Nhap hoanh do (cot) va tung do (hang) cua diem:" ; cin >> x >> y ; cout << " Nhap ma mau cua diem: " ; ...

Chúng ta hãy xem lại phương thức nhapsl của lớp DIEM

void DIEM::nhapsl()
    {
    cout <<"
Nhap hoanh do (cot) va tung do (hang) cua diem:" ;
    cin >> x >> y ;
    cout << " 
Nhap ma mau cua diem: " ;
    cin >> m ;
    }
    

Rõ ràng trong phương thức này chúng ta sử dụng tên các thuộc tính x, y và m một cách đơn độc. Điều này có vẻ như mâu thuẫn với quy tắc sử dụng thuộc tính nêu trong mục trước. Song sự thể như sau:

C++ sử dụng con trỏ đặc biệt this trong các phương thức. Các thuộc tính viết trong phương thức được hiểu là thuộc một đối tượng do con trỏ this trỏ tới. Như vậy phương thức nhapsl() có thể viết một cách tường minh như sau:

void DIEM::nhapsl()
    {
    cout << "
Nhap hoanh do (cot) va tung do (hang) cua diem:" ;
    cin >> this->x >> this->y ;
    cout << " 
Nhap ma mau cua diem: " ;
    cin >> this->m ;
    }
    

Từ góc độ hàm số có thể kết luận rằng: Phương thức bao giờ cũng có ít nhất một đối là con trỏ this và nó luôn luôn là đối đầu tiên của phương thức.

Xét một lời gọi tới phương thức nhapsl() :

DIEM d1;

d1.nhapsl() ;

Trong trường hợp này tham số truyền cho con trỏ this chính là địa chỉ của d1:

this = &d1

Do đó:

this->x chính là d1.x

this->y chính là d1.y

this->m chính là d1.m

Như vậy câu lệnh

d1.nhapsl() ;

sẽ nhập dữ liệu cho các thuộc tính của đối tượng d1. Từ đó có thể rút ra kết luận sau:

Tham số truyền cho đối con trỏ this chính là địa chỉ của đối tượng đi kèm với phương thức trong lời gọi phương thức.

Ngoài đối đặc biệt this (đối này không xuất hiện một cách tường minh), phương thức còn có các đối khác được khai báo như trong các hàm. Đối của phương thức có thể có kiểu bất kỳ (chuẩn và ngoài chuẩn).

Để xây dựng phương thức vẽ đường thẳng qua 2 điểm ta cần đưa vào 3 đối: Hai đối là 2 biến kiểu DIEM, đối thứ ba kiểu nguyên xác định mã mầu. Vì đã có đối ngầm định this là đối thứ nhất, nên chỉ cần khai báo thêm 2 đối. Phương thức có thể viết như sau:

void DIEM::doan_thang(DIEM d2, int mau)

{

int mau_ht;

mau_ht = getcolor();

setcolor(mau);

line(this->x,this->y,d2.x,d2.y);

setcolor(mau_ht);

}

Chương trình sau minh hoạ các phương thức có nhiều đối. Ta vẫn dùng lớp DIEM nhưng có một số thay đổi:

+ Bỏ thuộc tính m (mầu)

+ Bỏ các phương thức hien và an

+Đưa vào 4 phương thức mới:

ve_ doan_thang (Vẽ đoạn thẳng qua 2 điểm)

ve_tam_giac (Vẽ tam giác qua 3 điểm)

do_dai (Tính độ dài của đoạn thẳng qua 2 điểm)

chu_vi (Tính chu vi tam giác qua 3 điểm)

Chương trình còn minh hoạ:

+ Việc phương thức này sử dụng phương thức khác (phương thức ve_tam_giac sử dụng phương thức ve_doan_thang, phương thức chu_vi sử dụng phương thức do_dai)

+ Sử dụng con trỏ this trong thân các phương thức ve_tam_giac và chu_vi

Nội dung chương trình là nhập 3 điểm, vẽ tam giác có đỉnh là 3 điểm vừa nhập sau đó tính chu vi tam giác.

#include <conio.h>
    #include <iostream.h>
    #include <graphics.h>
    #include <math.h>
    #include <stdio.h>
    class DIEM
    {
    private:
    int x, y ;
    public:
    void nhapsl();
    void ve_doan_thang(DIEM d2, int mau) ;
    void ve_tam_giac(DIEM d2, DIEM d3,int mau) ;
    double do_dai(DIEM d2)
    {
    DIEM d1 = *this ;
    return sqrt( pow(d1.x - d2.x,2) + pow(d1.y - d2.y,2) ) ;
    }
    double chu_vi(DIEM d2, DIEM d3);
    };
    void DIEM::nhapsl()
    {
    cout <<" 
Nhap hoanh do (cot) va tung do (hang) cua diem:" ;
    cin >> x >> y ;
    }
    void kd_do_hoa()
    {
    int mh, mode ;
    mh=mode=0;
    initgraph(&mh, &mode, "");
    }
    void DIEM::ve_doan_thang(DIEM d2, int mau)
    {
    setcolor(mau);
    line(this->x,this->y,d2.x,d2.y);
    }
    void DIEM::ve_tam_giac(DIEM d2, DIEM d3,int mau)
    {
    (*this).ve_doan_thang(d2,mau);
    d2.ve_doan_thang(d3,mau);
    d3.ve_doan_thang(*this,mau);
    }
    double DIEM::chu_vi(DIEM d2, DIEM d3)
    {
    double s;
    s= (*this).do_dai(d2) + d2.do_dai(d3) + d3.do_dai(*this) ;
    return s;
    }
    void main()
    {
    DIEM d1, d2, d3;
    char tb_cv[20] ;
    d1.nhapsl();
    d2.nhapsl();
    d3.nhapsl();
    kd_do_hoa();
    d1.ve_tam_giac(d2,d3,15);
    double s = d1.chu_vi(d2,d3);
    sprintf(tb_cv,"Chu vi = %0.2f", s);
    outtextxy(10,10,tb_cv);
    getch();
    closegraph();
    }
    

Một số nhận xét về đối của phương thức và lời gọi phương thức

+ Quan sát nguyên mẫu phương thức:

void ve_doan_thang(DIEM d2, int mau) ;

sẽ thấy phương thức có 3 đối:

Đối thứ nhât là một đối tượng DIEM do this trỏ tới

Đối thứ hai là đối tượng DIEM d2

Đối thứ ba là biến nguyên mau

Nội dung phương thức là vẽ một đoạn thẳng đi qua các điểm *this và d2 theo mã mầu mau. Xem thân của phương sẽ thấy được nội dung này:

void DIEM::ve_doan_thang(DIEM d2, int mau)
    {
    setcolor(mau);
    line(this->x,this->y,d2.x,d2.y);
    }
    

Tuy nhiên trong trương hợp này, vai trò của this không cao lắm, vì nó được đưa vào chỉ cốt làm rõ đối thứ nhất. Trong thân phương thức có thể bỏ từ khoá this vẫn được.

+ Vai trò của this trở nên quan trọng trong phương thức ve_tam_giac:

void ve_tam_giac(DIEM d2, DIEM d3,int mau) ;

Phương thức này có 4 đối là:

this trỏ tới một đối tượng kiểu DIEM

d2 một đối tượng kiểu DIEM

d3 một đối tượng kiểu DIEM

mau một biến nguyên

Nội dung phương thức là vẽ 3 cạnh:

cạnh 1 đi qua *this và d2

cạnh 2 đi qua d2 và d3

cạnh 3 đi qua d3 và *this

Các cạnh trên được vẽ nhờ sử dụng phương thức ve_doan_thang:

Vẽ cạnh 1 dùng lệnh: (*this).ve_doan_thang(d2,mau) ;

Vẽ cạnh 2 dùng lệnh: d2.ve_doan_thang(d3,mau);

Vẽ cạnh 3 dùng lệnh: d3.ve_doan_thang(*this,mau);

Trong trường này rõ ràng vai trò của this rất quan trọng. Nếu không dùng nó thì công việc trơ nên khó khăn, dài dòng và khó hiểu hơn. Chúng ta hãy so sánh 2 phương án:

Phương án dùng this trong phương thức ve_tam_giac:

void DIEM::ve_tam_giac(DIEM d2, DIEM d3,int mau)
    {
    (*this).ve_doan_thang(d2,mau);
    d2.ve_doan_thang(d3,mau);
    d3.ve_doan_thang(*this,mau);
    }
    

Phương án không dùng this trong phương thức ve_tam_giac:

void DIEM::ve_tam_giac(DIEM d2, DIEM d3,int mau)
    {
    DIEM d1;
    d1.x = x;
    d1.y = y;
    d1.ve_doan_thang(d2,mau);
    d2.ve_doan_thang(d3,mau);
    d3.ve_doan_thang(d1,mau);
    }
    
0