實驗3 構造函數與析構函數(P279)

實驗目的和要求

  1、熟悉類的定義格式和類中成員的訪問權限。

  2、構造函數與析構函數的調用時機與順序。

  3、掌握對象的定義以及對象的初始化的時機與方法。

實驗內容

  1、下面程序sy3_1.cpp中用ERROR標明的語句有錯,在不刪除和增加代碼行的情況下,改正錯誤語句,使其正確運行。

//sy3_1.cpp
#include<iostream>
using namespace std;
class Aa
{
  public:
      Aa(int i=0){a=i;cout<<"Constructor"<<a<<endl;}
      ~Aa(){cout<<"Destructor"<<a<<endl;}
      void print(){cout<<a<<endl;}
  private:
    int a;
};
int main()
{
    Aa a1(1),a2(2);
    a1.print();
   cout<<a2.a<<endl;//ERROR
    return 0;
}

運行結果如下:


修改程序如下:

//sy3_1.cpp
#include<iostream>  
using namespace std;  
class Aa  
{  
  public:  
      Aa(int i=0){a=i;cout<<"Constructor"<<a<<endl;}  
      ~Aa(){cout<<"Destructor"<<a<<endl;}  
      void print(){cout<<a<<endl;}  
  private:  
    int a;  
};  
int main()  
{  
    Aa a1(1),a2(2);  
    a1.print();  
    a2.print();  
    return 0;  
}

正確程序運行結果如下:



2、調試下列程序。

//sy3_2.cpp
#include<iostream>
using namespace std;
class TPoint
{
public:
    TPoint(int x,int y){X=x,Y=y;}
    TPoint(TPoint &p);
    ~TPoint(){cout<<"Destructor is called\n";}
    int getx(){return X;}
    int gety(){return Y;}
private:
    int X,Y;
};
TPoint::TPoint(TPoint &p)
{
    X=p.X;
    Y=p.Y;
    cout<<"Copy-initialization Constructor is called\n";
}
int main()
{
    TPoint p1(4,9);
    TPoint p2(p1);
    TPoint p3=p2;
    TPoint p4,p5(2);
    cout<<"p3=("<<p3.getx()<<","<<p3.gety()<<")\n";
    return 0;
}

在該程序中,將TPoint類的帶有兩個參數的構造函數進行修改,在函數體內增加下述語句:

cout<<"Constructor is called.\n";

(1)寫出程序的輸出結果,並解釋輸出結果。

修改程序如下:

//sy3_2.cpp
#include<iostream>
using namespace std;
class TPoint
{
public:
    TPoint(int x,int y){X=x,Y=y;}
    TPoint(TPoint &p);
    ~TPoint(){cout<<"Destructor is called\n";}
    int getx(){return X;}
    int gety(){return Y;}
private:
    int X,Y;
};
TPoint::TPoint(TPoint &p)
{
    X=p.X;
    Y=p.Y;
    cout<<"Copy-initialization Constructor is called\n";
    cout<<"Constructor is called\n";
}
int main()
{
    TPoint p1(4,9);
    TPoint p2(p1);
    TPoint p3=p2;
    cout<<"p3=("<<p3.getx()<<","<<p3.gety()<<")\n";
    return 0;
}


原程序運行結果如下:

修改後的程序運行結果如下:


輸出結果解釋:


(2)按下列要求進行調試:

在主函數體內,添加下列說明語句:

TPoint  P4,P5(2);

//sy3_2.cpp
#include<iostream>
using namespace std;
class TPoint
{
public:
    TPoint(int x,int y){X=x,Y=y;}
    TPoint(TPoint &p);
    ~TPoint(){cout<<"Destructor is called\n";}
    int getx(){return X;}
    int gety(){return Y;}
private:
    int X,Y;
};
TPoint::TPoint(TPoint &p)
{
    X=p.X;
    Y=p.Y;
    cout<<"Copy-initialization Constructor is called\n";
    cout<<"Constructor is called\n";
}
int main()
{
    TPoint P4,P5(2);
    TPoint p1(4,9);
    TPoint p2(p1);
    TPoint p3=p2;
    cout<<"p3=("<<p3.getx()<<","<<p3.gety()<<")\n";
    return 0;
}
運行結果如下:


調試程序會出現什麼現象?爲什麼?如何解決?(提示:對已有的構造函數進行適當修改)結合運行結果分析如何使用不同的構造函數創建不同的對象。

出現的現象:


爲什麼:因爲在類中沒有定義不帶參數和帶一個參數的構造函數;

如何解決:將帶兩個參數的構造函數改爲缺省的構造函數,就是可以將TPoint(int x,int y)改爲TPoint(int x=0,int y=0) ; 在運行過程中,TPoint p1(4,9)和TPoint p4,p5(2);調用了構造函數,而TPoint p2(p1)和TPoint p3=p2是使用了拷貝構造函數。如下所示:

//sy3_2.cpp
#include<iostream>
using namespace std;
class TPoint
{
public:
    TPoint(int x=0,int y=0){X=x,Y=y;}
    TPoint(TPoint &p);
    ~TPoint(){cout<<"Destructor is called\n";}
    int getx(){return X;}
    int gety(){return Y;}
private:
    int X,Y;
};
TPoint::TPoint(TPoint &p)
{
    X=p.X;
    Y=p.Y;
    cout<<"Copy-initialization Constructor is called\n";
    cout<<"Constructor is called\n";
}
int main()
{
    TPoint P4,P5(2);
    TPoint p1(4,9);
    TPoint p2(p1);
    TPoint p3=p2;
    cout<<"p3=("<<p3.getx()<<","<<p3.gety()<<")\n";
    return 0;
}


3、對教材中Li3_11.cpp的主函數做如下修改:

(1)將Heapclass *pa1,*pa2 改爲Heapclass *pa1,*pa2,*pa3;

(2)在語句pa2=new Heapclass 後增加語句pa3=new Heapclass(5);

(3)將語句 if(!pa1||!pa2) 改爲if(!pa1||!pa2||!pa3)

(4)在語句delete pa2 後增加語句delete pa3;

寫出程序的輸出結果,並解釋輸出結果。

原程序如下:

//程序Li3_11.cpp
//new和delete的用法
#include<iostream>  
using namespace std;  
class Heapclass  
{  
    public:  
    Heapclass(int x);  
    Heapclass();  
    ~Heapclass();  
    private:  
    int i;  
};  
Heapclass::Heapclass(int x)  
{  
    i=x;  
    cout<<"Contstructor is called."<<i<<endl;  
}  
Heapclass::Heapclass()  
{  
cout<<"Default Contstructor is called."<<endl;  
}  
Heapclass::~Heapclass()  
{  
cout<<"Default is called."<<endl;  
}  
int main()  
{  
Heapclass *pa1,*pa2,*pa3;  
pa1=new Heapclass(4);  
pa2=new Heapclass;  
pa3=new Heapclass(5);  
if(!pa1||!pa2||!pa3);  
{  
    cout<<"Out of Memory!"<<endl;  
    return 0;  
}  
cout<<"Exit main"<<endl;  
delete pa1;  
delete pa2;  
delete pa3;  
return 0;  
}
原程序輸出結果如下:


解釋:pa1、pa2、pa3中是2個指向類Heapclass的對象指針,在能夠賦給它們足夠內存的情況下,使用運算符new給它們賦值,同時對它們所指向的對象進行初始化。使用delete釋放這三個指針所指向的對象,由於不能夠賦給pa1、pa2或pa3足夠內存,所以輸出“Out of Memory”。

4、請定義一個矩形類(Rectangle),私有數據成員爲矩形的長度(len)和寬度(wid),無參構造函數置len和wid爲0,有參構造函數置len和wid爲對應形參的值,另外還包括求矩形周長、取矩形面積、取矩形長度和寬度、修改矩形長度和寬度爲對應形參的值、輸出矩形尺寸等公有成員函數。要求輸出矩形尺寸的格式爲“length:長度,width:寬度”。(sy3_3.cpp)

//sy3_4.cpp
#include<iostream>
using namespace std;
class Rectangle
{
public:
   Rectangle()
   {
       len=0;
       wid=0;
   }
   Rectangle(double Len,double Wid)
   {
       len=Len;
       wid=Wid;
    }
   double Circumference()
   {
       return 2*(len+wid);
    }
   double Area()
   {
       return len*wid;
    }
   double getl()
   {
       return len;
    }
   double getw()
   {
       return wid;
    }
   void charge(double a,double b)
   {
       len=a;
       wid=b;
    }
   void s()
   {
       cout<<"length:"<<len<<"  "<<"width:"<<wid<<endl;
    }
private:
    int len,wid;
};
int main()
{
  Rectangle q;
  Rectangle h(5.0,2.0);
  cout<<"q的矩形尺寸:"<<endl;
  q.s();
  cout<<"h的矩形尺寸:"<<endl;
  h.s();
  cout<<"h的周長:"<<h.Circumference()<<endl;
  cout<<"h的面積:"<<h.Area()<<endl;
  cout<<"h的長度:"<<h.getl()<<endl;
  cout<<"h的寬度:"<<h.getw()<<endl;
  h.charge(8.0,6.0);
  cout<<"修改後的矩形的尺寸:"<<endl;
   h.s();
   return 0;
}
運行結果如下:



分析與討論

  1、類中私有成員的訪問權限。

    答:私有成員是被隱藏的數據,只有該類的成員函數或友元函數纔可以引用它。

  2、構造函數與析構函數的調用順序。

    答:構造函數在創建對象的時候被調用,析構函數在釋放對象的時候被調用,釋放由構造函數分配的內存,構造函數與析構函數的調用順序正好相反。

  3、何時進行對象初始化?如何進行?(提示:注意分一般對象和堆對象討論)

    答:一般對象:在對象創建時進行初始化,可以用構造函數或拷貝函數進行初始化。

        堆對象:使用運算符new分配內存,調用構造函數來進行初始化。

實驗總結

    在這次實驗中我學會了構造函數與析構函數的使用,掌握了它們的調用方法與調用順序,當然對類的定義格式和類中成員的訪問權限也更加的熟悉,同時還掌握了拷貝函數的使用方法,雖然對知識點的掌握不是很牢固,在編寫程序時因爲對知識點不能熟練運用,會導致不知道該怎麼去構造這個程序,頭腦裏沒有清晰地思路,在寫程序前先不要着急寫,應該先弄清楚所寫得程序要運用到哪些基本知識,自己如果對某個知識不熟悉就得鞏固一下,再按照題目要求弄清這個程序的思路,我相信通過長期反覆的訓練最終也會熟能生巧。

    這次實驗的過程不是非常的順利,在編寫程序是,由於疏忽大意將private的p寫成大寫的,並且把文件格式存錯了,本該是.cpp爲後綴的,存成了.c爲後綴,導致一直運行都出現錯誤,在一次次的排查之後才找到了問題的出處,所以,在寫程序是一定要細心,只有細心纔能有所所獲。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章