实验目的和要求
1、熟悉类的定义格式和类中成员的访问权限。
2、构造函数与析构函数的调用时机与顺序。
3、掌握对象的定义以及对象的初始化的时机与方法。
实验内容
1、下面程序sy3_1.cpp中用ERROR标明的语句有错,在不删除和增加代码行的情况下,改正错误语句,使其正确运行。
- #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;
- }
运行结果如下:
修改程序如下:
- #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、调试下列程序。
- #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)写出程序的输出结果,并解释输出结果。
修改程序如下:
- #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);
- #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是使用了拷贝构造函数。如下所示:
- #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;
写出程序的输出结果,并解释输出结果。
原程序如下:
- #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)
- #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分配内存,调用构造函数来进行初始化。
实验总结
在这次实验中我学会了构造函数与析构函数的使用,掌握了它们的调用方法与调用顺序,当然对类的定义格式和类中成员的访问权限也更加的熟悉,同时还掌握了拷贝函数的使用方法,虽然对知识点的掌握不是很牢固,在编写程序时因为对知识点不能熟练运用,会导致不知道该怎么去构造这个程序,头脑里没有清晰地思路,在写程序前先不要着急写,应该先弄清楚所写得程序要运用到哪些基本知识,自己如果对某个知识不熟悉就得巩固一下,再按照题目要求弄清这个程序的思路,我相信通过长期反复的训练最终也会熟能生巧。