Trang 3 trên tổng số 3 Đầu tiênĐầu tiên 123
Từ 21 tới 30 trên tổng số 30 kết quả

Đề tài: Lập trình C++ | Tài liệu lập trình C++ của Phạm Văn Ất

  1. #21
    Ngày gia nhập
    12 2006
    Bài viết
    72

    Mặc định Lập trình C++ | Tài liệu lập trình C++ của Phạm Văn Ất

    Tiếp tục phần 2:
    Các chú ý:
    +) Chú ý 1: Phương thức tĩnh:
    Để tạo một đối tượng TAM_GIAC từ 3 đối tượng DIEM ta dung phương thức tĩnh:
    static TAM_GIAC tao_tg(DIEM e1,DIEM e2,DIEM e3)
    {
    TAM_GIAC t;
    t.d1=e1;t.d2=e2;t.d3=e3;
    return t;
    }
    Phương thức tĩnh có các đặc điểm sau:
    1,Giống như các phương thức thong thường là trong thân của nó truy nhập tới các thành phần của lớp (cụ thể là lớp TAM_GIAC)
    2, Khác các phương thức thường ở chỗ:
    Không có đối ngầm định xác định bởi con trỏ this(như phương thức thông thường). Như vậy,phương thức TAM_GIAC có đúng 3 đối.
    Không gần với một đối tượng cụ thể nào của lớp,nên trong lời gọi tới phương thức ảo có thể dung tên lớp,xem hàm main() ta thất có đoạn: “t=TAM_GIAC::tao_tg(d[i],d[j],d[k]);”
    +) Chú ý 2: Không thể thay phương thức tĩnh tao_tg bằng hàm, vì trong thân của hàm không được truy xuất đến các thuộc tính của lớp TAM_GIAC, tuy nhiên có thể có một giải pháp khác là dung khái niệm hàm bạn (friend). Hàm bạn của một lớp có quyền truy nhập đến các thuộc tính của lớp. Và để minh họa ta sẽ xây dựng hàm tao_tg như một hàm bạn của lớp TAM_GIAC.
    Ví dụ 3: Minh họa cách dung hàm bạn. Nội dung chương trình sẽ giống như ví dụ 2:
    Code:
     #include<conio.h>
    #include<iostream.h>
    #include<math.h>
    class DIEM
      {
        private:
            double x,y; // Toa do cua diem
        public:
            void nhapsl()
              {
                cout<<” Toa do x,y cua diem: “;
                cin>>x>>y;
             }
            void in()
             {
               cout<<” x= “<<x<<” y= “<<y;
             }
            double do_dai(DIEM d2)
              {
                return sqrt(pow(x-d2.x,2)+pow(y-d2.y,2));
              }
      };
    class TAM_GIAC
        {
          private:
              DIEM d1,d2,d3; //3 dinh cua tam giac
          public:
              void nhapsl();
              void in();
          friend TAM_GIAC tao_tg(DIEM e1,DIEM e2,DIEM e3)
              {
                TAM_GIAC t;
                 t.d1=e1;t.d2=e2;t.d3=e3;
                 return t;
              }
          double  dien_tich();
          TAM_GIAC maxdt(TAM_GIAC t2);
       };
    void TAM_GIAC::nhapsl()
       {
         cout<<”\n Dinh 1: “;
         d1.nhapsl();
         cout<<”\n Dinh 2: “;
         d2.nhapsl();
         cout<<”\n Dinh 3: “;
         d3.nhapsl();
       }
    void TAM_GIAC::in()
       {
         cout<<”\n Dinh 1: “;d1.in();
         cout<<”\n Dinh 2: “;d2.in();
         cout<<”\n Dinh 3: “;d3.in();
       }
    double  TAM_GIAC::dien_tich()
        {
          double a,b,c,p,s;
          a=d1.do_dai(d2);
          b=d2.do_dai(d3);
          c=d3.do_dai(d1);
          p=(a+b+c)/2;
          return sqrt(p*(p-a)*(p-b)*(p-c));
        }
    TAM_GIAC TAM_GIAC::maxdt(TAM_GIAC t2)
        {
          if(this->dien_tich()>t2.dien_tich())
            return *this;
         else
            return t2;
        }
    void main()
         {
           DIEM d[50];
           int n,i;
           clrscr();
           cout<<”\n So diem= “;
           cin>>n;
           for(i=1;i<=n;i++)
             {
              cout<<”\n Nhap diem: “<<i<<” : “;
              d[i].nhapsl();
             }
           int j,k;
          TAM_GIAC tmax,t;
          tmax=TAM_GIAC::tao_tg(d[1],d[2],d[3]);
          for(i=1;i<=n-2;i++)
             for(j=i+1;j<=n-1;j++)
               for(k=j+1;k<=n;k++)
                  {
                    t=TAM_GIAC::tao_tg(d[i],d[j],d[k]);
                    tmax=tmax.maxdt(t);
                  }
          cout<<”\n\n Tam giac co dien tich lon nhat: “;
          tmax.in();
          cout<<”\n Dien tich = “<<tmax.dien_tich();
          getch();
      }
    Chú ý: Hàm bạn có thể xây dựng trong định nghĩa lớp như trong ví dụ trên hoặc có thể khai báo bên trong và xây dựng bên ngoài định nghĩa lớp như sau:
    class TAM_GIAC
    {
    private:
    DIEM d1,d2,d3;
    public:
    void nhapsl();
    void in();
    friend TAM_GIAC tao_tg(DIEM e1,DIEM e2,DIEM e3);
    double dien_tich();
    TAM_GIAC maxdt(TAM_GIAC t2);
    };
    TAM_GIAC tao_tg(DIEM e1,DIEM e2,DIEM e3)
    {
    TAM_GIAC t;
    t.d1=e1;t.d2=e2;t.d3=e3;
    return t;
    } Nhận xét: Không cho dung từ khóa friend khi xây dựng hàm bên ngoài lớp

  2. #22
    Ngày gia nhập
    12 2006
    Bài viết
    72

    §6 : Hàm và hàm bạn
    6.1 Hàm có các tính chất sau:
    Phạm vi hoạt động của hàm là toàn bộ chương trình,vì vậy hàm có thể được gọi tới từ bất kì chỗ nào. Như vậy trong các phương thức có thể sử dụng hàm
    đối của hàm có thể là các đối tượng, tuy nhiên có một số hạn chế là trong than hàm không cho phép truy nhập tới thuộc tính của các đối này.Ví dụ giả sử đã định nghĩa lớp:
    class DIEM
    {
    private:
    double x,y; //toạ độ cuẩ điểm
    public :
    void nhapsl()
    {
    cout<< « \n toa do x,y : « ;
    cin>>x>>y ;
    }
    void in()
    {
    cout<< « x= »<<x<< y= »<<y ;
    }
    } ;

    Dùng lớp DIEM ta xây dựng 1 hàm tính độ dài đoạn thẳng đi qua 2 điểm như sau :
    double do_dai(DIEM d1,DIEM d2)
    {
    return sqrt(pow(d1.x-d2.x,2)+pow(d1.y-d2.y,2)) ;
    }

    Hàm này sẽ bị báo lỗi khi dịch, vì trong thân hàm không cho phép sử dụng các thuộc tính d1.x,d2.x,d1.y,d2.y của các đối tượng d1,d2 của lớp DIEM
    + Phạm vi sử dụng của các phương thức (public) là toàn chương trình, vì vậy trong thân hàm có thể gọi tới các phương thức. Ví dụ : giả sử đã định nghĩa lớp :
    class DIEM
    {
    private :
    double x,y ;// Toa độ của điểm
    public :
    void nhapsl()
    {
    cout<< »\n Toa do x,y : « ;
    cin>>x>>y ;
    }
    void in()
    {
    cout<< » x= « <<x<< » y= « <<y ;
    }
    double do_dai(DIEM d2)
    {
    return sqrt(pow(x-d2.x,2)+pow(y-d2.y,2)) ;
    }
    } ;

    Khi đó bằng cách dùng phương thức do_dai,ta có thể viết hàm tính diện tích của tam giác có đỉnh là các đối tượng d1,d2,d3 của lớp DIEM như sau :
    double dt_tg(DIEM d1,DIEM d2,DIEM d3)
    {
    double a,b,c,p,s ;
    a=d1.do_dai(d2) ;
    b=d2.do_dai(d3) ;
    c=d3.do_dai(d1) ;
    p=(a+b+c)/2
    return sqrt(p*(p-a)*(p-b)*(p-c)) ;
    }

    Bằng cách dùng hàm dt_tg có thể tổ chức lại chương trình tìm tam giác có diện tích lớn nhất(ở mục trên) một cách đơn giản hơn(bỏ đi lớp TAM_GIAC) như ví dụ sau :
    Ví dụ 1 :
    Code:
    #include<conio.h>
    #include<iostream.h>
    #include<math.h>
    class DIEM
        {
           private :
              double x,y ; //Toa do cua diem
           public :
              void nhapsl()
                       {
                          cout<< »\n Toa do x,y : « ;
                          cin>>x>>y ;
                       }
                     void in()
                        {
                           cout<< » x= « <<x<< » y= « <<y ;
                        }
                     double do_dai(DIEM d2)
                         {
                           return sqrt(pow(x-d2.x,2)+pow(y-d2.y,2)) ;
                         }
         } ;
    double dt_tg(DIEM d1,DIEM d2,DIEM d3)
                    {
                      double a,b,c,p,s ;
                       a=d1.do_dai(d2) ;
                       b=d2.do_dai(d3) ;
                       c=d3.do_dai(d1) ;
                       p=(a+b+c)/2 ;
                       return sqrt(p*(p-a)*(p-b)*(p-c)) ;
                    }
    void main()
         {
            DIEM d[50] ;
            int n,i,j,k,imax,jmax,kmax ;
            clrscr() ;
            cout<< »\n so diem = « ;
            cin>>n ;
            for(i=1 ;i<=n ;i++)
              {
                cout<< »\n Nhap diem « <<i<< » : « ;
                d[i].nhapsl() ;
              }
            imax=1 ;jmax=2 ;kmax=3 ;
            for(i=1 ;i<=n-2 ;i++)
              for(j=i+1 ;j<=n-1 ;j++)
                 for(k=j+1 ;k<=n ;k++)
                    if(dt_tg(d[i],d[j],d[k])>dt_tg(d[imax],d[jmax],d[kmax])
                       {
                         imax=i ;
                         jmax=j ;
                         kmax=k ;
                       }
            cout<< »\n tam giac co dien tich lon nhat : « ;
            cout<< »\n Dinh 1 : « ;d[imax].in() ;
            cout<< »\n Dinh 2 : « ;d[jmax].in() ;
            cout<< »\n Dinh 3 : « ;d[kmax].in() ;
            getch() ;
       }
    Nhận xét : Chương trình trên làm việc trên mảng d kiểu DIEM. Bây giờ nếu ta dùng mảng ngoài thì số thứ tự sẽ suy ra phần tử của mảng. Như vậy hàm :
    double dt_tg(DIEM d1,DIEM d2,DIEM d3) ;
    có 3 đối kiểu DIEM có thể thay bằng 3 đối nguyên :
    double dt_tg(int i,int j,int k) ;
    để tính diện tích tam giác có đỉnh là d[i],d[j],d[k]. Ý tưởng này được thực hiên trong ví dụ sau :
    Code:
    #include<iostream.h>
    #include<conio.h>
    #inlcude<math.h>
    double dt_tg(int i,int j,int k) ; // Khai bao ham dt_tg
    class DIEM
       {
          private :
              double x,y ; //Toa do cua diem
          public :
              void nhapsl() ;
              void in() ;
          double do_dai(DIEM d2) ;
       } ;
    // Khi khai bao mang kieu DIEM thi phai khai bao sau dinh nghia lop DIEM
    DIEM d[50] ;
    void DIEM ::nhapsl()
        {
           cout<< » toa do x,y : « ;
           cin>>x>>y ;
        }
    void DIEM ::in()
        {
           cout<< » x= « << x<<»  y= «<< ;
        }
    void DIEM ::do_dai(DIEM d2)
        {
          return sqrt(pow(x-d2.x,2)+pow(y-d2.y,2)) ;
        }
    double dt_tg(int i,int j,int k)
         {
           double a,b,c,p,s ;
           a=d[i].do_dai(d[j]) ;
           b=d[j].do_dai(d[k]) ;
           c=d[k].do_dai(d[i]) ;
           p=(a+b+c)/2 ;
           return sqrt(p*(p-a)*(p-b)*(p-c)) ;
         }
    void main()
         {
           int n,i,j,k,imax,jmax,kmax ;
           clrscr() ;
           cout<< »\n So diem : « ;
           cin>>n ;
           for(i=1 ;i<=n ;i++)
             { 
                cout<< »\n nhap diem thu « <<i<< » : » ;
                d[i].nhapsl() ;
             }
           imax=1 ;jmax=2 ;kmax=3 ;
           for(i=1 ;i<=n-2 ;i++)
               for(j=i+1 ;j<=n-1 ;j++)
                  for(k=j+1 ;k<=n ;k++)
                     if(dt_tg(i,j,k)>dt_tg(imax,jmax,kmax))
                         {
                           imax=i ;
                           jmax=j ;
                           kmax=k ;
                         }
          cout<< »\n tam giac co dien tich lon nhat la : « ;
          cout<< »\n dinh 1 : « ;d[imax].int() ;
          cout<< »\n dinh 2 : « ;d[jmax].in() ;
          cout<< »\n dinh 3 : « ;d[kmax].in() ;
          cout<< »\n voi dien tich la : « <<dt_tg(imax,jmax,kmax) ;
          getch() ;
        }
    6.2 : Hàm bạn (friend function)
    6.2.1 : Để một hàm trở thành hàm bạn của một lớp có 2 cách :
    cách 1 : Dùng từ khoá friend để khai báo hàm trong lớp và xây dựng hàm bên ngoài như các hàm thông thường (không dùng từ khoá friend). Mẫu viết như sau :
    class A
    {
    private :
    // Khai báo thuộc tính.
    public :
    .....
    //Khai báo hàm bạn của lớp A
    friend void f1(...) ;
    friend double f2(...) ;
    friend A f3(...) ;
    ....
    } ;

    sau đó xây dựng các hàm f1,f2,f3 bên ngoài định nghĩa lớp theo mẫu :
    void f1(...)
    {
    .........
    }
    double f2(....)
    {
    ...........
    }
    A f3(...)
    {
    .........
    }

    Cách 2 : Dùng từ khoá friend để xây dựng hàm trong định nghĩa lớp theo mẫu :
    class A
    {
    private :
    // Khai báo các thuộc tính
    public :
    ........
    // Xây dựng các hàm bạn của lớp A
    friend void f1(...)
    {
    .....
    }
    friend double f2(....)
    {
    .....
    }
    friend A f3(....)
    {
    ....
    }
    } ;

  3. #23
    Ngày gia nhập
    12 2006
    Bài viết
    72

    Mặc định Bài 6: Hàm và hàm bạn(tiếp theo)

    6.2.2 : Các tính chất của hàm bạn
    Trong thân hàm bạn của một lớp có thể truy nhập tới các thuộc tính của các đối tượng thuộc lớp này, đây là sự khác nhau duy nhất giữa hàm bạn và các hàm thông thường. Chú ý rằng hàm bạn không phải là phương thức của lớp. Phương thức có một đối ẩn (ứng với con trỏ this) và lời gọi tới các phương thức phải gắn với một đối tượng nào đó (đia chỉ của đối tượng này được truyền tới con trỏ this. Lời gọi của hàm bạn thì giống như các hàm thông thường.
    Trong ví dụ sau sẽ so sánh hàm bạn ,phương thức và hàm tự do (hàm thông thường. Xét một lớp SP (số phức). Hãy so sánh 3 phương án để thực hiện việc cộng 2 số phức
    Phương án 1 : Dùng phương thức :
    class SP
    {
    private ;
    double a ;// Phần thực
    double b ; // Phần ảo
    public :
    SP cong(SP u2)
    {
    SP u ;
    u.a=this->a+u2.a ;
    u.b=this->b+u2.b ;
    return u ;
    }
    } ;

    Cách dùng :
    SP u,u1,u2 ;
    u=u1.cong(u2) ;
    phương án 2 : Dùng hàm bạn
    class SP
    {
    private ;
    double a ;// Phần thực
    double b ; // Phần ảo
    public :
    friend SP cong(SP u1,SP u2)
    {
    SP u ;
    u.a=u1.a+u2.a ;
    u.b=u2.b+u2.b ;
    return u ;
    }
    } ;

    Cách dùng :
    SP u,u1,u2 ;
    u=cong(u1,u2) ;
    Phương án 3 : Dùng hàm thông thường_hàm tự do
    class SP
    {
    private ;
    double a ;// Phần thực
    double b ; // Phần ảo
    public :
    SP cong(SP u1,SP u2)
    {
    SP u ;
    u.a=u1.a+u2.a ;
    u.b=u2.b+u2.b ;
    return u ;
    }
    } ;

    Ghi chú : Phương án này không được chấp nhận ,trình biên dịch sẽ báo lỗi vì trong thân hàm không được quyền truy suất tới các thuộc tính riêng (private) của đối tượng u,u1,u2 thuộc lớp SP
    6.2.3 : Một hàm có thể là hàm bạn của nhiều lớp được không ?
    Câu trả lời là được, khi một hàm là hàm bạn của nhiều lớp thì nó có quyền truy nhập tới tất cả các thuộc tính của các đối tượng trong các lớp này. Để làm cho hàm f trở thành hàm bạn của các lớp A,B,C ta sử dụng mẫu viết sau :
    class A ; // Khai báo trước lớp A
    class B ; // Khai báo trước lớp B
    class C ; //Khai báo trước lớp C
    // Định nghĩa lớp A
    class A
    {
    private :
    ..... // Khai báo các thuộc tính của lớp A
    public :
    //Khai báo f là hàm bạn của lớp A
    friend void f(...) ;
    } ;
    Tương tự ta cũng làm như trên đối với các lớp B và C như sau :
    class B
    {
    private :
    ..... // Khai báo các thuộc tính của lớp B
    public :
    //Khai báo f là hàm bạn của lớp B
    friend void f(...) ;
    } ;
    class C
    {
    private :
    ..... // Khai báo các thuộc tính của lớp C
    public :
    //Khai báo f là hàm bạn của lớp C
    friend void f(...) ;
    } ;
    //Sau khi khai báo như trên ta đi xây dựng hàm f
    void f(...)
    {
    .......
    }
    Chương trình sau đây minh hoạ cách dùng hàm bạn( bạn của một lớp và bạn của nhiều lớp). Chương trình đưa vào 2 lớp VT (vectơ), MT (ma trận) và 3 hàm để thực hiện thao tác trên 2 lớp này
    //Hàm bạn với lớp VT dùng để in 1 vectơ
    friend void in(const VT &x) ;
    // Hàm bạn với lớp MT dùng để in 1 ma trận
    friend void in(const MT &a) ;
    // Hàm bạn với cả 2 lớp MT và VT dùng để nhân ma trận với vectơ
    Nội dung của chương trình là nhập một ma trận vuông cấp n và một vectơ cấp n, sau đó thực hiện phép nhân ma trận với vectơ vừa nhập
    Chương trình :
    Code:
    #include<conio.h>
    #include<iostream.h>
    #include<math.h>
    class VT ;
    class MT ;
    class VT
        {
          private :
               int n ;
               double x[20] ;
          public :
               void nhapsl() ;
               friend void in(const VT &x) ;
               friend VT tich(const MT &a,const VT &x) ;
         } ;
    class MT
         {
           private :
                int n ;
                double a[20][20] ;
           public :
                friend VT tich(const MT &a,const VT &x) ;
                friend void in(const MT &a) ;
                void nhapsl() ;
          } ;
    void VT ::nhapsl() 
           {
             cout<< »\n nhap cap cua vecto : « ;
             cin>>n ;
             for(int i=1;i<=n ;i++)
                {
                   cout<< »\n phan tu thu « <<i<< » : » ;
                   cin>>x[i] ;
                }
           }
    void MT ::nhapsl()
           {
             cout<< »\n nhap cap cua ma tran : « ;cin>>n ;
             for(int i=1 ;i<=n ;i++)
                for(j=1 ;j<=n ;j++)
                    {
                       cout<< »\n phan tu hang « <<i<< » cot « <<j<< » : » ;
                       cin>>a[i][j] ;
                    }
    VT tich(const MT &a,const VT &x)
            {
              VT y ;
               int n=a.n ;
               if(n !=x.n)
               return x ;
               y.n=n ;
               for(int i=1 ;i<=n ;i++)
                  {
                    y.x[i]=0 ;
                     for(int j=1 ;j<=n ;j++)
                        y.x[i]+=a.a[i][j]*x.x[j] ;
                  }
                return y ;
            }
    void in(const VT &x)
            {
               cout<< »\n » ;
               for(int i=1 ;i<=x.n ;i++)
                  cout<<x.x[i]<< » « ;
            }
    void in(const MT &a)
            {
              for(int i=1 ;i<=a ;i++)
                 {
                   cout<< »\n » ;
                   for(int j=1 ;j<=a.n ;j++)
                     cout<<a.a[i][j]<< » « ;
                  }
             }
    void main()
           {
               MT a ;VT x,y ;
               clrscr() ;
               a.nhapsl() ;
               x.nhapsl() ;
               y=tich(a,x) ;
               clrscr() ;
               cout<< »\n Ma tran A : « ;
               in(a) ;
               cout<< »\n\n Vecto x : « ;
               in(x) ;
               cout<< »\n\n Vecto y=Ax : « ;
               in(y) ;
               getch() ;
           }

  4. #24
    Ngày gia nhập
    12 2006
    Bài viết
    72

    Mặc định Bai 7 : Phạm Vi Truy Xuất

    7.1. Các từ khoá private và public
    Các thành phần (thuộc tính và phương thức) của lớp có thể khai báo là private hoặc public theo mẫu :
    private :
    //Khai báo các thành phần riêng của lớp
    public :
    // Khai báo các thành phần chung (công cộng)
    chú ý : các thành phần khai báo mặc định (không dùng các từ khoá private hay public) được xem là thành phần private.
    7.2.Các thành phần riêng của lớp.
    Chỉ được sử dụng trong phạm vi của lớp (trong thân các phương thức của lớp).Chúng không thể đem ra sử dụng bên ngoài lớp
    +) Một thuộc tính private : Thuộc tính này của một đối tượng nào đó chỉ có thể sử dụng trong thân các phương thức cùng lớp.
    Để làm rõ hơn khái niệm này ta có thể xét ví dụ sau : Xét một lớp PS(phân số) với 2 thuộc tính nguyên là t(tử) và m(mẫu). Giả sử cần xây dựng các phương thức để thực hiện các phép toán như cộng , trừ, nhân , chia 2 phân số. Do các phép toán này cần dùng trong toàn bộ chương trình, nên các phương thức dùng để thực hiện các phép toán cần được khai báo là public. Để thực hiện các phép toán trên phân số cần dùng đến phép rút gọn phân số. Ta có thể dùng một phương thức private để thực hiện điều này do việc rút gọn chỉ dùng trong nội bộ lớp.
    7.3. Các thành phần công cộng của lớp
    Có phạm vi sử dụng là toàn bộ chương trình .Như vậy nếu một thuộc tính được khai báo là public thì có thể được truy nhập trong thân của bất kì hàm nào trong chương trình.
    Ví dụ trong bài 6 đã chỉ ta phương án dùng một hàm (tự do) để thực hiện việc cộng 2 số phức như sau là sai :
    Phương án 3 : Dùng hàm thông thường_hàm tự do
    class SP
    {
    private ;
    double a ;// Phần thực
    double b ; // Phần ảo
    public :
    SP cong(SP u1,SP u2)
    {
    SP u ;
    u.a=u1.a+u2.a ;
    u.b=u2.b+u2.b ;
    return u ;
    }
    } ;

    Tuy nhiên nếu sửa chữa bằng cách thay từ khoá private thành từ khoá public thì lại được.
    Nhận xét : Các thuộc tính thường được khai báo là private để đảm bảo tính dấu kín, an toàn dữ liệu của lớp.

  5. #25
    Ngày gia nhập
    12 2006
    Bài viết
    72

    Mặc định Bài 8 : Các phương thức toán tử

    8.1.Cách đặt tên
    Các phương thức toán tử được xây dựng như các phương thức thông thường.Chỉ có khác cách đặt tên. Tên của các phương thức toán tử cũng giống như hàm toán tử được tạo bằng cách ghép từ khoá operator với một phép toán :
    Ví dụ : operator+, operator-,operator<<,operator>>....
    8.2. Con trỏ this
    Cũng giống như phương thức thông thường, phương thức toán tử có đối đầu tiên (đối không tường minh) là con trỏ this.
    8.3.Toán tử một toán hạng
    Các phương thức toán tử một toán hạng :dùng ngay con trỏ this để biểu thị toán hạng duy nhất này, nên trong phương thức sẽ không có đối tường minh. Ví dụ phương thức toán tử - (đổi dấu) một đối tượng kiểu SP (số phức) có thể viết như sau :
    class SP
    {
    private :
    double a ;//phần thực
    double b ;//phần ảo
    public :
    SP operator-() ;
    } ;
    SP SP ::operator-()
    {
    SP u ;
    u.a=-this->a ;
    u.b=-this->b ;
    return u ;
    }
    cách dùng :
    SP u,v ;
    u=-v ;
    8.4.Toán tử có 2 toán hạng
    Các phương thức toán tử hai toán hạng : con trỏ this ứng với toán hạng thứ nhất, nên trong phương thức chỉ cần dùng 1 đối tường minh để biểu thị toán hạng thứ hai. Ví dụ phương thức toán tử + (cộng) hai đối tượng kiểu SP (số phức) có thể viết như sau :
    class SP
    {
    private :
    double a ;//phần thực
    double b ;//phần ảo
    public :
    SP operator+(SP u2) ;
    } ;
    SP SP ::operator-()
    {
    SP u ;
    u.a=-this->a +u2.a;
    u.b=-this->b +u2.b;
    return u ;
    }
    Cách dùng :
    SP p,q,r ;
    r=p+q ;
    8.5. Lớp DT (đa thức)
    Chương trình sau sẽ định nghĩa lớp DT đa thức và đưa vào các phương thức,hàm :
    +Các thuộc tính :
    int n ; //bậc của đa thức
    double *a ; //Trỏ tới vùng nhớ chứa các hệ số của đa thức
    +Các phương thức :
    operator+,operator- :dùng để đổi dấu các hệ số của đa thức
    operator+ :cộng 2 đa thức
    operator- :trừ 2 đa thức
    operator* :Nhân 2 đa thức
    operator^ :tính giá trị của đa thức
    operator[] : cho biết bậc và các hệ số của đa thức
    +Các hàm bạn :
    operator<< :dùng để in các hệ số của đa thức
    operator>> : dùng để nhập các hệ số của đa thức
    + Hàm (tự do)
    double F(DT p,double x) dùng để tính p(x)_giá trị của đa thức tại x
    +Nói thêm về phương thức chỉ số và hàm tự do F
    -Nếu p là đối tượng của lớp DT, thì hàm chỉ số cho biết :
    p[-1]=double(n)
    p[i]=a[i], i=0,1,...,n
    -Hàm tự do F sẽ dùng phương thức chỉ số để xác định n, các hệ số đa thức và dùng chúng để tính giá trị của biểu thức
    +Trong chương trình sử dụng hàm new để cấp phát vùng nhớ chứa hệ số của đa thức
    +Nội dung của chương trình gồm :
    -Nhập,in các đa thức p,q,r,s
    -Tính đa thức :f=-(p+q)*(r-s)
    -Nhập các số thực x1 và x2
    -Tính f(x1) bằng cách dùng phương thức operator^
    -Tính f(x2) bằng cách dùng hàm F
    //Chương trình được viết như sau :
    Code:
    #include<iostream.h>
    #include<conio.h>
    #include<math.h>
    class DT
       {
         private :
              int n ; //Bac cua da thuc
              double *a ; //Tro toi vung nho chua he so cua da thuc :a0,a1,...
         public :
              friend ostream& operator<<(ostream& os,const DT &d) ;
              friend istream& operator>>(istream& is,DT &d) ;
         DT operator-() ;
         DT operator+(const DT &d2) ;
         DT operator-(DT d2) ;
         DT operator*(const DT &d2) ;
         double operator^(const double &x) ;//tinh gia tri cua da thuc
         double operator[](int i)
           {
             if(i<0)
                return double(n)
             else
                return a[i] ;
           }
       } ;
    //Ham tinh gia tri cua da thuc
    double F(DT d,double x)
        {
          double s=0.0,t=1.0 ;
          int n ;
          n=int(d[-1]) ;
          for(int i=0 ;i<=n ;i++)
            {
              s+=d[i]*t ;
              t*=x ;
            }
          return s ;
        }
    ostream& operator<<(ostream& os,const DT &d)
        {
           os<< » Cac he so (tu a0) : » ;
           for(int i=0 ;i<=d.n ;i++)
              os<<d.a[i]<< » « ;
           return os ;
        }
    istream& operator>>(istream& is,DT &d)
        {
           cout<< »\n bac cua da thuc : « ;
           cin>>d.n ;
           d.a=new double[d.n+1] ;
           cout<< »\n nhap cac he so cua da thuc : \n ;
           for(int i=0 ;i<=d.n ;i++)
             {
               cout<< »\n he so bac « <<i<< » = « ;
               is>>d.a[i] ;
             }
            return is ;
         }
    DT DT ::operator-()
         {
           DT p ;
           p.n=n ;
           p.a=new double[n+1] ;
           for(int i=0 ;i<=n ;i++)
             p.a[i]=-a[i] ;
           return p ;
         }
    DT DT ::operator+(const DT &d2)
         {
           DT d ;
           int  k,i ;
           k=n>d2.n ?n ::d2.n ;
           d.a=new double[k+1] ;
           for(i=0 ;i<=k ;i++)
             if(i<=n&&i<=d2.n)
               d.a[i]=a[i]+d2.a[i] ;
             else if(i<=n)
                d.a[i]=a[i] ;
             else
                d.a[i]=d2.a[i] ;
           i=k ;
           while(i>0&&d.a[i]==0.0) –i ;
           d.n=i ;
           return d ;
         }
    DT DT ::operator-(DT d2)
          {
            return(*this+(-d2)) ;
          }
    DT DT ::operator*(const DT &d2)
          {
            DT d ;
            int k,i,j ;
            k=d.n=n+d2.n ;
            d.a=new double[k+1] ;
            for(i=0 ;i<=k ;i++) d.a[i]=0 ;
            for(i=0 ;i<=n ;i++)
              for(j=0 ;j<=d2.n ;j++)
                   d.a[i+j]+=a[i]*d2.a[j] ;
            return d ;
          }
    double DT ::operator^(const double &x)
          {
             double s=0.0,t=1.0 ;
             for(int i=0 ;i<=n ;i++)
                {
                  s+=a[i]*t ;
                  t*=x ;
                }
              return s ;
           }
    void main()
         {
           DT p,q,r,s,f ;
           double x1,x2,g1,g2 ;
           clrscr() ;
           cout<< »\n nhap da thuc P « ;cin>>p ;
           cout<< »\n Da thuc P » <<p ;
           cout<< »\n nhap da thuc Q « ;cin>>q ;
           cout<< »\n da thuc Q : « <<q ;
           cout<< »\n nhap da thuc R « ;cin>>r ;
           cout<< »\n Da thuc R » <<r ;
           cout<< »\n nhap da thuc S « ;cin>>s ;
           cout<< »\n Da thuc S » <<s ;
           f=-(p+q)*(r-s) ;
           cout<< »\n nhap so thuc x1 : « ;cin>>x1 ;
           cout<< »\n nhap so thuc x2 : « ;cin>>x2 ;
           g1=f^x1 ;
           g2=F(f,x2) ;
           cout<< »\n Da thuc F « <<f ;
           cout<< »\n f(« <<x1<< »)= « <<g1 ;
           cout<< »\n f(« <<x2<< »)= « <<g2 ;
           getch() ;
         }

  6. #26
    Ngày gia nhập
    12 2006
    Bài viết
    72

    Mặc định Chương 4 : HÀM TẠO,HÀM HUỶ VÀ CÁC VẤN ĐỀ LIÊN QUAN

    Chương này trình bày một số vẫn đề có tính chuyên sâu hơn về lớp như :
    + hàm tạo (constructor)
    + hàm huỷ (destructor)
    + toán tử gán và hàm tạo sao chép
    + mối liên quan giữa hàm tạo và đối tượng thành phần
    + Các thành phần tĩnh
    + lớp bạn,hàm bạn
    + đối tượng hằng
    + phương thức inline
    bài 1 : Hàm tạo (constructor)
    1.1.Công dụng
    Hàm tạo cũng là một phương thức của lớp (nhưng khá đặc biệt) dùng để tạo dựng một đối tượng mới. Chương trình dịch sẽ cấp phát bộ nhớ cho đối tượng sau đó sẽ gọi đến hàm tạo. Hàm tạo sẽ khởi gán giá trị cho các thuộc tính của đối tượng và thực hiện một số công việc khác nhằm chuẩn bị cho đối tượng mới.
    1.2.Cách viết hàm tạo
    1.2.1 : Điểm khác nhau của hàm tạo và các phương thức thông thường
    Khi viết hàm tạo ta cần chú ý 3 sự khác nhau giữa hàm tạo so với các phương thức khác như sau :
    +Tên của hàm tạo : Bắt buộc tên hàm tạo phải trùng với tên của lớp
    +Không khai báo kiểu cho hàm tạo
    +Hàm tạo không có kết quả trả về
    1.2.2 : Điểm giống nhau của hàm tạo và các phương thức thông thường
    Ngoài 3 điểm khác nhau trên thì hàm tạo được viết giống như các phương thức khác :
    +Hàm tạo có thể được xây dựng bên trong hoặc bên ngoài định nghĩa lớp
    +Hàm tạo có thể có đối hoặc không có đối
    +Trong một lớp có thể có nhiều hàm tạo (cùng tên nhưng khác bộ đối)
    Để minh hoạ cho các điều vừa nói ta xet ví dụ sau :
    giả sử ta có một lớp DIEM_DH (điểm đồ hoạ) có 3 thuộc tính như sau :
    int x ; //hoành độ (hàng) của điểm
    int y ; //tung độ (cột) của điểm
    int m ; //mã mầu của điểm
    Và bây giờ ta đưa vào 2 hàm tạo để khởi gán cho các thuộc tính của lớp,
    vì ở đây chúng ta đang làm quen với hàm tạo nên chúng ta không nhất thiểt phải quan tâm xem xây dựng 2 hàm đó để làm gì _tức là công dụng của 2 hàm đó,mà chúng ta chỉ quan tâm xem hàm đó xây dựng như thế nào.
    Hàm thứ nhất : là hàm tạo không đối,dùng các giá trị cố định để khởi gán cho x,y,m
    Hàm thứ hai : là hàm tạo có đối,dùng các đối x1,y1,m1 để khởi gán giá trị cho x,y và mặc định m1=15 (mầu trắng)
    Và để minh hoạ cho vị trí của hàm tạo,hàm không đối sẽ được viêt bên trong định nghĩa lớp,còn hàm có đối sẽ được xây dựng bên ngoài định nghĩa lớp.
    class DIEM_DH
    {
    private :
    x,y,m ;
    public :
    DIEM_DH()
    {
    x=y=0 ; //khởi gán giá trị cho x và y là 0
    m=1 ; //Khởi gán giá trị cho m là 1
    }
    DIEM_DH(int x,int y,int m=15) ;
    // Các phương thức khác nếu có
    } ;
    DIEM_DH :IEM_DH(int x1,int y1,int m1=15)
    {
    x=x1 ;y=y1 ;m=m1 ;
    }
    1.3.Dùng hàm tạo trong khai báo
    + Sau khi đã xây dựng được các hàm tạo , ta có thể dùng chúng trong khai báo để tạo ra 1 đối tượng,đồng thời khởi gán cho các thuộc tính của đối tượng được tạo. Dựa vào các tham số trong khai báo mà trình biên dịch biết sẽ phải gọi đến hàm tạo nào.
    + Khi khai báo một biến đối tượng có thể sử dụng các tham số để khởi gán cho các thuộc tính của biến đối tượng.
    + Khi khai báo mảng đối tượng không cho phép dùng các tham số để khởi gán
    + Câu lệnh khai báo một biến đối tượng sẽ gọi tới hàm tạo một lần.
    + Câu lệnh khai báo một mảng n đối tượng sẽ gọi tới hàm tạo n lần
    ví dụ :
    DIEM_DH d: // Gọi tới hàm tạo không đối,kết quả d.x= d.y =0 , d.m=1
    DIEM_DH u(200,100,4) ;// gọi tới hàm tạo có đối,kết quả u.x=200,u.y=100,u.m=4
    DIEM_DH v(300,250) ;// Gọi tới hàm tạo có đối,kết quả v.x=300,v.y=250,v.m=15
    DIEM_DH p[10] ; // Gọi tới hàm không đối 10 lần
    Chú ý : Với các hàm có đối kiểu lớp,thì đối chỉ xem là tham số hình thức, vì vậy khai báo đối (trong dòng đầu của hàm) sẽ không tạo ra đối tượng mới và do đó không gọi tới hàm tạo
    1.4. Dùng hàm tạo trong cấp phát bộ nhớ
    + Khi cấp phát bộ nhớ cho một đối tượng có thể dùng các tham số để khởi gán cho các thuộc tính của đối tượng. Ví dụ :
    DIEM_DH *q=new DIEM_DH(50,40,6) //gọi tới hàm có đối
    // Kết quả : q->x=50,q->y=40,q->m=6
    DIEM_DH *r=new DIEM_DH ; //Gọi tới hàm tạo không đối
    // Kết quả r->x=0,r->y=0,r->m=1
    + Khi cấp phát bộ nhớ cho một dãy đối tượng không cho phép dùng tham số để khởi gán,ví dụ :
    int n=20 ;
    DIEM_DH *s=new DIEM_DH[n] ; // Gọi tới hàm tạo không đối 20 lần
    1.5. Dùng hàm tạo để biểu diễn các đối tượng hằng
    + Như đã biết,sau khi định nghĩa lớp DIEM_DH thì có thể xem như lớp này như một kiể dữ liệu như int, float,long...
    Với kiểu int chúng ta có các hằng int như 1,2,36,...
    Với kiểu float chúng ta có các hằng như :11.25,2.8,...
    Từ đó ta có thể mở rộng khái niệm hằng kiểu DIEM_DH
    + Để biểu diễn một hằng đối tượng( hay còn gọi :Đối tượng hằng) chúng ta phải sử dụng hàm tạo. Mẫu viết như sau :
    Tên lớp(danh sách tham số) ;
    Ví dụ : đối với lớp DIEM_DH nói trên có thể viết như sau :
    DIEM_DH(345,123,8) //Biểu thị một đối tượng DIEM_DH có các thuộc tính
    // x=345,y=123 và m=8
    chú ý : Có thể sử dụng một hằng đối tượng như một đối tượng.Nói cách khác có thể dùng hằng đối tượng để thực hiện một phương thức,ví dụ nếu viết :
    DIEM_DH(345,123,8).in() ;
    Thì có nghĩa là thực hiện phương thức in() đối với hằng đối tượng.
    1.6.Ví dụ minh hoạ
    Trong ví dụ sau sẽ minh hoạ cách xây dựng hàm tạo và cách sử dụng hàm tạo trong khai báo, trong cấp phát bộ nhớ và trong việc biểu thị các hằng đối tượng

    Code:
    #include<conio.h>
    #include<iostream.h>
    #include<iomanip.h>
    class DIEM_DH
         {
           private :
              int x,y,m ;
           public :
              //ham ban dung de in doi tuong DIEM_DH
              friend void in(DIEM_DH d)
                {
                  cout<< »\n »<<d.x<< » « <<d.y<< » « <<d.m ;
                }
             //phuong thuc dung de in doi tuong DIEM_DH
              void in()
                {
                  cout<< »\n »<< d.x<< » « <<d.y<< » « <<d.m ;
                }
              // Ham tao khong doi
               DIEM_DH()
                  {
                    x=y=0 ;
                    m=1 ;
                  }
             //ham tao co doi,doi m1 co gia tri mac dinh la 15(mau trang)
                  DIEM_DH(int x1,int y1,int m1=15) ;
           } ;
    //xay dung ham tao
    DIEM_DH ::DIEM_DH(int x1,int y1,int m1=15)
           {
               x=x1 ;y=y1 ;m=m1 ;
           }
    void main()
         {
              DIEM_DH d1 ;//goi toi ham tao khong doi
              DIEM_DH d2(200,200,10) ; //goi toi ham tao co doi
              DIEM_DH *d ;
              d=new DIEM_DH(300,300)//goi toi ham tao co doi
              clrscr() ;
              in(d1) ;//goi toi ham ban in()
              d2.in() ;//goi toi phuong thuc in()
              in(*d) ;//goi toi ham ban in()
              DIEM_DH(2,2,2).in() ;//goi toi phuong thuc iin()
              DIEM_DH t[3] ;//3 lan goi toi ham tao khong doi
              DIEM_DH *q ;//goi toi ham tao khong doi
              int n ;
              cout<< »\n N= » ; cin>>n ;
              q=new DIEM_DH[n+1] ;//(n+1) lan goi toi ham tao khong doi
              for(int i=0 ;i<=n ;i++)
                 q[i]=DIEM_DH(300+i,200+i,8) ;//(n+1)lan goi toi ham tao co doi
              for(i=0 ;i<=n ;i++)
                 q[i].in() ;//goi toi phuong thuc in()
              for(i=0 ;i<=n ;i++)
                 DIEM_DH(300+i,200+1,8).in() ;//goi toi phuong thuc in()
              getch() ;
          }

  7. #27
    Ngày gia nhập
    12 2006
    Bài viết
    72

    Mặc định Bài 2 : LỚP KHÔNG CÓ HÀM TẠO VÀ HÀM TẠO MẶC ĐỊNH

    Các chương trình nêu trong chương 3 đều không có hàm tạo.Vậy khi đó các đối tượng được hình thành như thế nào ?
    2.1. Nếu lớp không có hàm tạo. Chương trình dịch sẽ cung cấp một hàm tạo mặc định không đối (default). Hàm này ngoài chức năng tạo ra đối tượng mới thông qua việc cấp phát bộ nhớ cho đối tượng thì không là gì khác. Chúng ta có thể kiểm chứng thông qua ví dụ sau :
    Code:
    #include<iostream.h>
    #include<conio.h>
    class DIEM_DH
         {
            private :
               int x,y,m ;
            public :
               //Phuong thuc
               void in()
                   {
                     cout<< »\n « <<x<< » « <<y<< » « <<m ;
                   }
         } ;
    void main()
           {
             DIEM_DH d ;
             d.in() ;
             DIEM_DH *p ;
             p=new DIEM_DH[10] ;
             clrscr() ;
             d.in() ;
             for(int i=0 ;i<=10 ;i++)
                 {
                   (p+i) ->in() ;
                 }
             getch() ;
           }
    2.2.Nếu trong lớp đã có ít nhất một hàm tạo thì hàm tạo mặc định sẽ không được phát sinh nữa. Khi đó mọi câu lệnh xây dựng đối tượng mới đều sẽ gọi đến hàm tạo của lớp. Nếu không tìm thấy hàm tạo được gọi thì chương trình dịch sẽ báo lỗi.Điều này thường xảy ra khi chúng ta không xây dựng hàm tạo không đối,nhưng lại sử dụng các khai báo không tham số như ví dụ sau :
    Code:
    #include<iostream.h>
    #include<conio.h>
    class DIEM_DH
          {
             private :
                 int x,y,m ;
             public :
             //phuong thuc dung de in doi tuong DIEM_DH
               void in()
                   {
                      cout<< »\n »<<x<< » « <<y<< » « <<m ;
                   }
             // Ham tao co doi
               DIEM_DH ::DIEM_DH(int x1,int y1,int m1)
                  {
                    x=x1 ;y=y1 ;m=m1 ;
                  }
         } ;
    void main()
       {
          DIEM_DH d1(200,200,10) ;//goi toi ham tao co doi
          DIEM_DH d2 ;//goi toi ham tao khong doi
          d2=DIEM_DH(300,300,8) ;//goi toi ham tao co doi
          d1.in() ;
          d2.in() ;
          getch() ;
       }
    Trong các câu lệnh trên chỉ có câu lệnh thứ 2 trong hàm main() là bị báo lỗi. Câu lệnh này sẽ gọi tới hàm tạo không đối,mà hàm này chưa được xây dựng trong lớp DIEM_DH
    để khắc phục lỗi trên có 2 giải pháp sau :
    thứ nhất : Xây dựng thêm hàm tạo không đối trong lớp DIEM_DH
    thứ hai : Gán giá trị mặc định cho tất cả các đối x1,y1,m1 của hàm tạo đã xây dựng ở trên.
    Theo cách thứ 2 thì chương trình có thể được viết lại như sau :
    Code:
    #include<iostream.h>
    #include<conio.h>
    class DIEM_DH
          {
             private :
                 int x,y,m ;
             public :
             //phuong thuc dung de in doi tuong DIEM_DH
               void in()
                   {
                      cout<< »\n »<<x<< » « <<y<< » « <<m ;
                   }
             // Ham tao co doi,tất cả các đối đều có giá trị mặc định
               DIEM_DH ::DIEM_DH(int x1=0,int y1=0,int m1=15)
                  {
                    x=x1 ;y=y1 ;m=m1 ;
                  }
         } ;
    void main()
       {
          DIEM_DH d1(200,200,10) ;//goi toi ham tao khong dung tham so mac dinh
          DIEM_DH d2 ;//goi toi ham tao,dung 3 tham so mac dinh
          d2=DIEM_DH(300,300) ;//goi toi ham tao dung 1 tham so mac dinh
          d1.in() ;
          d2.in() ;
          getch() ;
       }

  8. #28
    Ngày gia nhập
    12 2006
    Bài viết
    72

    Mặc định Bài 3 :lớp đa Thức

    Chương trình dưới đây là sự cải tiến của chương trình trong mục 8.5 của chương 3 bằng cách đưa vào 2 hàm tạo
    //hàm tạo không đối
    DT()
    {
    this->n=0 ;this->a=NULL ;
    }
    //hàm tạo có đối
    DT(int n1)
    {
    this->n=n1 ;
    this->a=new double[n1+1] ;
    }
    Hàm tạo có đối sẽ tạo một đối tượng mới (kiểu DT) gồm 2 thuộc tính là biến nguyên n và con trỏ a. Ngoài ra còn cấp phát một vùng nhớ cho a để chứa các hệ số của đa thức.
    Nếu không xây dựng hàm tạo,mà sử dụng hàm tạo mặc định thì các đối tượng (kiểu DT) tạo ra bởi các lệnh khai báo sẽ chưa có bộ nhớ để chứa đa thức. Như vậy đối tượng tạo ra chưa hoàn chỉnh và chưa dùng được.Để có một đối tượng hoàn chỉnh cần qua 2 bước :
    +Dùng khai báo để tạo các đối tượng,ví dụ :
    DT d ;
    +Cấp phát cùng nhớ cho đối tượng để chứa đa thức,ví dụ :
    d.n=m ;
    d.a=new double[m+1] ;
    qui trình này được áp dụng trong các phương thức toán tử trong chương trình mục 8.5 chương 3. Rõ ràng qui trình này vừa dài lại vừa không tiện lợi, vì người lập trình thường quên không cấp phát bộ nhớ.
    Việc dùng hàm tạo để sản sinh ra các đối tượng hoàn chỉnh tỏ ra tiện lợi hơn,vì tránh được các thao tác phụ (như cấp phát bộ nhớ) nằm ngoài khai báo.Phương án dùng hàm tạo sẽ được sử dụng trong cá phương thức toán tử của chương trình dưới đây :
    Nội dung của chương trình gồm :
    -nhập,in các đa thức p,q,r,s
    -tính đa thức : f=-(p+q)*(r-s)
    -nhập các số thực x1 và x2
    -tính f(x1) (bằng cách dùng phương thức operator^)
    -tính f(x2) (bằng cách dùng hàm F)
    chương trình được viết như sau :
    Code:
    #include<iostream.h>
    #include<conio.h>
    #include<math.h>
    class DT
     {
       private :
            int n ;//bac cua da thuc
            double *a ;//tro toi vung nho chua cac he so cua da thuc :a0,a1,a2...
       public :
            DT()
              {
                this->n=0 ;this->a=NULL ;
              }
            DT(int n1)
               {
                 this->n=n1 ;
                 this->a=new double[n1+1] ;
               }
            friend ostream& operator<<(ostream& os,const DT &d) ;
            friend istream& operator>>(istream& is,DT &d) ;
            DT operator-() ;
            DT operator+(const DT &d2) ;
            DT operator-(DT d2) ;
            DT operator*(const DT &d2) ;
            double operator^(const double &x); //tinh gia tri cua da thuc
            double operator[](int i);
               {
                 if(i<0)
                    return double(n);
                 else
                     return a[i];
               }
      };
    //ham tinh gia tri cua da thuc
     double F(DT d,double x)
           {
              double s=0.0,t=1.0;
              int n;
              n=int(d[-1]);
              for(int i=0;i<=n;i++)
                {
                  s+=d[i]*t;
                  t*=x;
                }
              return s;
          }
    ostream& operator<<(ostream& os,const DT &d)
         {
            os<<” Cac he so (tu a0): “;
            for(int i=0;i<=d.n,i++)
                 os<<d.a[i]<<” “;
           return os;
         }
    istream& operator>>(istream& is,DT &d)
         {
           if(d.a!=NULL) delete d.a;
           cout<<”\n bac cua da thuc : “;cin>>d.n;
           d.a=new double[d.n+1];
           cout<<”\n nhap cac he so cho da thuc: \n”;
           for(int i=0;i<=d.n;i++)
              {
                cout<<”\n he so bac “<<i<<” = “;
                is>>d.a[i];
              }
           return is;
        }
    DT DT::operator-()
         {
           DT p(this->n);
           for(int i=0;i<=n;i++)
              p.a[i]=-a[i];
           return p;
         }
    DT DT::operator+(const DT &d2)
         {
           int k,i;
           k=n>d2.n?n:d2.n;
           DT d(k);
           for(i=0;i<=k;i++)
             if(i<=n&&i<=d2.n)
                d.a[i]=a[i]+d2.a[i];
             else if(i<=n)
                d.a[i]=a[i];
             else
                d.a[i]=d2.a[i];
           i=k;
           while(i>0&&d.a[i]==0.0) –i;
           d.n=i;
           return d;
         }
    DT DT::operator-(DT d2)
         {
           return(*this+(-d2));
         }
    DT DT::operator*(const DT &d2)
         {
           int k,i,j;
           k=n+d2.n;
           DT d(k);
           for(i=0;i<=k;i++) d.a[i]=0;
              for(i=0;i<=n;i++)
                for(j=0;j<=d2.n;j++)
                  d.a[i+j]+=a[i]*d2.a[j];
           return d;
         }
    double DT::operator^(const double &x)
         {
           double s=0.0,t=1.0;
           for(int i=0;i<=n;i++)
             {
               s+=a[i]*t;  t*=x;
             }
           return s;
        }
    void main()
        {
          DT p,q,r,s,f;
          double x1,x2,g1,g2;
          clrscr();
          cout<<”\n nhap da thuc P “;cin>>p;
          cout<<”\n Da thuc P”<<p;
          cout<<”\n nhap da thuc Q “;cin>>q;
          cout<<”\n Da thuc Q”<<q;
          cout<<”\n nhap da thuc R “;cin>>r;
          cout<<”\n Da thuc R”<<r;
          cout<<”\n nhap da thuc S “;cin>>s;
          cout<<”\n Da thuc S”<<s;
          f=-(p+q)*(r-s);
          cout<<”\n nhap so thuc x1: “;cin>>x1;
          cout<<”\n nhap so thuc x1: “;cin>>x2;
          g1=f^x1;
          g2=F(f,x2);
          cout<<”\n Da thuc F “<<f;
          cout<<”\n f(“<<x1<<”)=”<<g1;
          cout<<”\n f(“<<x2<<”)=”<<g2;
          getch();
        }

  9. #29
    Ngày gia nhập
    12 2006
    Bài viết
    72

    § 4 Hàm tạo sao chép (copy constructor)
    4.1 Hàm tạo sao chép mặc định
    Giả sử đã định nghĩa một lớp nào đó, ví dụ lớp PS (phân số) . Khi đó:
    + Ta có thể dùng câu lệnh khai báo hoặc cấp phát bộ nhớ để tạo các đối tượng mới, ví dụ:
    PS p1,p2; //khai báo 2 biến kiểu PS
    PS *p=new PS; //cấp phát bộ nhớ cho 1 biến kiểu PS do p trỏ tới
    + Ta cũng có thể dùng lệnh khai báo để tạo ra một đối tượng mới từ một đối tượng đã tồn tại, ví dụ:
    PS u;
    PS v(u); //Tạo v theo u
    Ý nghĩa của các lệnh này như sau:
    - Nếu trường hợp Ps chưa xây dựng hàm tạo sao chép, thì câu lệnh này sẽ gọi một hàm tạo sao chép mặc định (của C++). Hàm này sẽ sao chép từng bit của u vào các bit tương ứng của v. Như vậy vùng nhớ của u và v sẽ có nội dung như nhau. Rõ rang,trong đa số các trường hợp,nếu không có các thuộc tính kiểu con trỏ hay tham chiếu,thì việc dùng các hàm tạo sao chép mặc định (để tạo ra một đối tượng mới có nội dung như đối tượng cho trước ) là đủ và không cần thiết để xây dựng một hàm tạo sao chép mới.
    - Nếu trong lớp PS đã có hàm tạo sao chép (cách viết sẽ được nói sau) thì câu lệnh:
    PS v(u);
    Tạo ra một đối tượng mới v sau đó gọi tới hàm tạo sao chép để khởi gán v theo u.
    Ví dụ sau minh họa 2 cách dùng hàm tạo sao chép mặc định:
    Trong chương trình đưa vào lớp PS (phân số):
    +Các thuộc tính gồm : t (tử số) và m (mẫu số)
    +Trong lớp không có phương thức nào cả mà chỉ có 2 hàm bạn là các hàm toán tử nhập (>>) và xuất(<<)
    + Nội dung của chương tình là : Dùng lệnh khai báo để tạo ra một đối tượng u kiểu PS có nội dung như đối tượng đã có d.

    Code:
    //Chương trình minh họa cách dùng hàm tạo sao chép mặc định
    #include<conio.h>
    #include<iostream.h>
    class PS
      {
        private
        int t,m;
    public:
    friend ostream& operator<<(ostream& os,const PS &p)
         {
            os<<”=  “<<p.t<<”/””<<p.m;
            return os;
         }
        friend istream& operator>>(istream& is,PS &p)
         {
           cout<<”- Nhap tu va mau: “;
            is>>p.t>>p.m;
            return is;
         }
    };
    void main()
    {
      PS d;
       cout<<”\n Nhap PS d: “;cin>>d;
       cout<<”\n PS d: “<<d;
       PS u(d);
       cout<<”\n  PS u “<<u;
       getch();
    }
    4.2 Cách xây dựng hàm tạo sao chép
    + Hàm tạo sao chép sử dụng một đối kiểu tham chiếu đối tượng để khởi gán cho đối tượng mới. Hàm tạo sao chép được viết theo mẫu:
    Tên_lớp (const Tên_lớp & dt)
    {
    //Các câu lệnh dùng các thuộc tính của đối tượng dt để khởi gán cho các thuộc tính
    // của đối tượng mới
    }
    + Ví dụ có thể xây dựng hàm tạo sao chép cho lớp PS như sau:
    class PS
    {
    private:
    int t,m;
    public :
    PS(const PS &p)
    {
    this->t=p.t;
    this->m=t.m;
    }
    ………
    };
    4.3. Khi nào cần xây dựng hàm tạo sao chép
    + Nhận xét: Hàm tạo sao chép trong ví dụ trên không khác gì so với hàm tạo sao chép mặc định
    + Khi lớp không có các thuộc tính kiểu con trỏ hay tham chiếu thì chỉ cần dùng hàm tạo sao chép mặc định là đủ
    + Khi lớp có các thuộc tính kiểu con trỏ hay tham chiếu thì dùng hàm tạo sao chép là chưa đáp ứng được yêu cầu. Ví dụ lớp DT (đa thức) trong §3
    class DT
    {
    private:
    int n; //Bậc đa thức
    double *a; //Trỏ tới cùng nhớ chứa các hệ số a0,a1,…
    public:
    DT()
    {
    this->n=0; this->a=NULL;
    }
    DT(int n1)
    {
    this->n=n1;
    this->a=new double[n1+1];
    }
    friend ostream& operator<<(ostream& os,const DT &d);
    friend istream& operator>>(istream& is,const DT &d);
    …………
    };
    Tuy nhiên khi dùng hàm tạo sao chép mặc định đôi khi dẫn đến một số nhầm lẫn , ta sẽ tìm hiểu điều đó trong ví dụ sau:
    DT d; // Tạo một đối tượng mới kiểu DT
    cin>>d;
    /* Nhập đối tượng d gồm: nhập một số nguyên dương và gán cho d,n,cấp phát vùng nhớ cho d.a,nhập các hệ số của đa thức và chứa vào vùng nhớ được cấp phát
    */
    DT u(d);
    /* dùng hàm tạo sao chwps mặc định để xây dựng đối tượng u theo d,kết quả u.n=d.n và
    u.a=d.a. Như vậy 2 con trỏ u.a và d.a cùng trỏ tới một vùng nhớ.
    */
    Nhận xét: Mục đích của chúng ta là tạo ra một đối tượng u giống đối tượng d, nhưng độc lập với d. Nghĩa là khi d thay đổi thì u không bị ảnh hưởng gì. Nhưng qua phân tích ví dụ trên ta thấy điều này không đạt được vì u và d dùng chung một vùng nhớ,do đó khi một trong 2 đối tượng này thay đổi thì đối tượng kia cũng bị thay đổi theo. Ngoài ra,nếu một trong 2 đối tượng bị giải phóng bộ nhớ thì đối tượng kia cũng không còn bộ nhớ nữa.

  10. #30
    Ngày gia nhập
    12 2006
    Bài viết
    72

    Mặc định Hàm tạo sao chép (tiếp & hết)

    Ví dụ sau sẽ minh họa cho nhận xét trên: Khi u thay đổi thì d cũng thay đổi và ngược lại khi d thay đổi thì u cũng thay đổi theo
    Code:
    #include<conio.h>
    #include<iostream.h>
    #include<math.h>
    class DT
       {
         private:
           int n;  //Bac cua da thuc
           double *a; //Tro toi vung nho chua cac he so cua da thuc a0,a1…
         public:
            DT()
               {
                 this->n=0;
                 this->a=NULL;
               }
            DT(int n1)
               {
                  this->n=n1;
                  this->a=new double[n1+1];
               }
           friend ostream& operator<<(ostream& os,const DT &d);
           friend istream& operator>>(istream& is,DT &d);
      };
    ostream& operator<<(ostream& os,const DT &d)
      {
        os<<”-Cac he so (tu a0): “;
        for(int i=0;i<d.n;i++)
           os<<d.a[i]<<” ”;
       return os;
     }
    istream& operator>>(istream& is,DT &d)
     {
       if(d.a!=NULL) delete d.a;
       cout<<”- Bac cua da thuc: “;
       cin>>d.n;
       d.a=new double[d.n+1];
       cout<<”\n Nhap cac he so cua da thuc: \n”;
       for(int i=0;i<d.n;i++)
         {
           cout<<”\n He so bac “<<i<<” = “;
           is>>d.a[i];
         }
      return is;
     }
    void main()
      {
        DT d;
        clrscr();
        cout<<”\n Nhap da thuc d “;cin>>d;
        DT u(d);
        cout<<”\n Da thuc d “<<d;
        cout<<”\n Da thuc u “<<u;
        cout<<”\n Nhap da thuc d: “;cin>>d;
        cout<<”\n Da thuc d “<<d;
        cout<<”\n Da thuc u “<<u;
        cout<<”\n Nhap da thuc u: “;cin>>u;
        cout<<”\n Da thuc d “<<d;
        cout<<”\n Da thuc u “<<u;
        getch();
      }
    4.4.Ví dụ về hàm tạo sao chép
    Trong chương trình trên đã chỉ rõ hàm tạo sao chép mặc đinh là chưa đủ đối với lớp DT. Vì vậy cần viết hàm tạo sao chép để xây dựng đối tượng mới (ví dụ u) từ một đối tượng đã tồn tại (ví dụ d) theo các yêu cầu sau:
    + Gán d.n cho u.n
    + Cấp phát một vùng nhớ cho u.a để có thể chứa được (d.n+1) hệ số
    + Gán các hệ số chứa trong vùng nhớ của d.a sang vùng nhớ của u.a
    Như vậy ta sẽ tạo được một đối tượng mới u có nội dung giống như d nhưng độc lập với d.
    Để đáp ứng yêu cầu trên,hàm tạo sao chép cần được xây dựng như sau:
    DT:T(const DT &d)
    {
    this->n=d.n;
    this->a=new double[d.n+1];
    for(int i=0;i<=d.n;i++)
    this->a[i]=d.a[i];
    }
    Chương trình sau sẽ minh họa cho điều này,sự thay đổi của d không làm ảnh hưởng gì tới u và ngược lại sự thay đổi của u không làm ảnh hương gì tới d.
    Code:
    #include<conio.h>
    #include<iostream.h>
    #include<math.h>
    class DT
      {
        private:
           int n; //Bac cua da thuc
           double *a; 
        public:
           DT()
             {
               this->n=0;this->a=NULL;
             }
           DT(int n1)
             {
               this->n=n1;
               this->a=new double[d.n+1];
             }
           DT(const DT &d)
                 friend ostream& operator<<(ostream& os,const DT &d);
                 friend istream& operator>>(istream& is,DT &d);
            };
         DT::DT(const DT &d)
          {
        this->n=d.n;
        this->a=new double[d.n+1];
        for(int i=0;i<=d.n;i++)
           this->a[i]=d.a[i];
                    }
         ostream& operator<<(ostream& os,const DT &d)
          {
            os<<”-Cac he so (tu a0): “;
            for(int i=0;i<d.n;i++)
            os<<d.a[i]<<” ”;
            return os;
           }
         istream& operator>>(istream& is,DT &d)
          {
            if(d.a!=NULL) delete d.a;
            cout<<”- Bac cua da thuc: “;
            cin>>d.n;
            d.a=new double[d.n+1];
            cout<<”\n Nhap cac he so cua da thuc: \n”;
            for(int i=0;i<d.n;i++)
             {
              cout<<”\n He so bac “<<i<<” = “;
              is>>d.a[i];
             }
            return is;
          }
         void main()
                    {
        DT d;
        clrscr();
        cout<<”\n Nhap da thuc d “;cin>>d;
        DT u(d);
        cout<<”\n Da thuc d “<<d;
        cout<<”\n Da thuc u “<<u;
        cout<<”\n Nhap da thuc d: “;cin>>d;
        cout<<”\n Da thuc d “<<d;
        cout<<”\n Da thuc u “<<u;
        cout<<”\n Nhap da thuc u: “;cin>>u;
        cout<<”\n Da thuc d “<<d;
        cout<<”\n Da thuc u “<<u;
        getch();
                    }

Các đề tài tương tự

  1. Biệt thự văn phú, liền kề văn phú, căn góc, hướng đẹp, giá ưu đãi
    Gửi bởi ephat_tt86 trong diễn đàn Giới thiệu website, sản phẩm của bạn
    Trả lời: 0
    Bài viết cuối: 14-12-2011, 09:12 AM
  2. Liền kề văn phú, dự án văn phú, giá bán = gốc + chênh thấp
    Gửi bởi ephat_tt86 trong diễn đàn Giới thiệu website, sản phẩm của bạn
    Trả lời: 0
    Bài viết cuối: 07-12-2011, 11:40 AM
  3. Liền kề Văn Phú TT28, bán Liền kề Văn Phú TT2, TT9, TT12, TT33
    Gửi bởi datphat191 trong diễn đàn Giới thiệu website, sản phẩm của bạn
    Trả lời: 0
    Bài viết cuối: 20-10-2011, 12:10 PM

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn