實驗目的和要求
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爲後綴,導致一直運行都出現錯誤,在一次次的排查之後才找到了問題的出處,所以,在寫程序是一定要細心,只有細心纔能有所所獲。