实验三 构造函数与析构函数

不羁岁月 提交于 2019-12-07 07:37:53

实验目的和要求

  1. 熟悉类的定义格式和类中成员的访问权限。
  2. 构造函数与析构函数的调用时机与顺序。
  3. 掌握对象的定义以及对象的初始化的时机与方法。

实验内容

1. 下面程序sy3_1.cpp中用ERROR标明的语句有错,在不删除和增加代码行的情况下,改正错误语句,使其正确运行。

//sy_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
    a2.print();
    return 0;
}

源程序已被注释。添加修改后程序。
运行结果
这里写图片描述
结果分析:
这里写图片描述

  1. a是私有数据。所以main函数不能访问并输出a2.a。所以改为a2.print()
  2. 该程序中定义了两个对象a1和a2。类中有两个构造函数。a1用成员选择运算符“.”访问成员函数print()。 创建对象a1,a2时调用有一个参数构造函数,输出第一二行结果。a1,a2用成员选择运算符“.”访问成员函数print(),输出第三四行结果。然后运行析构函数输出第五六行结果。

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 p1(4,9);
    TPoint p2(p1);
    TPoint p3=p2;  //用对象P2创建新对象P3。
    cout<<"p3=("<<p3.getx()<<","<<p3.gety()<<")\n";
    return 0;
}

在该程序中,将TPoint类的带有两个参数的构造函数进行修改,在该函数体内添加下述语句:cout<<""Constrcutor is called.\n;
1. 写出程序的输出结果,并解释输出结果。
输出结果:
这里写图片描述
结果分析:
该程序声明了三个对象p1,p2和p3。类中有三个构造函数。创建对象p1时调用有两个参数的构造函数TPoint(int x,int y){X=x; Y=y;}。创建对象p2时调用有一个参数的构造函数,输出一二行,创建对象p3时调用有一个参数的构造函数,输出第三四行。然后执行输出语句cout<<"p3=("<<p3.getx()<<","<<p3.gety()<<")\n";调用有一个参数的get函数,输出第五行结果。最后分别执行析构函数输出后续结果。

2.按下列要求进行调试:在主函数体内添加下列说明语句:TPoint P4,P5(2);调试程序会出现什么现象?为什么?如何解决?(对已有的构造函数进行修改)结合运行结果分析如何使用不同的构造函数创建不同的对象。
调试结果:
这里写图片描述
这是由于类class中没有定义TPoint::TPoint()函数,所以不能执行这个语句。
解决方法:

//sy3_2.cpp
#include<iostream>
using namespace std;
class TPoint
{
public:
    TPoint();       //无参构造函数
    TPoint(int a);      //有一个参数的构造函数
    TPoint(int x,int y){X=x; Y=y;}  //有两个参数的构造函数
    TPoint(TPoint &p);      //拷贝构造函数
    ~TPoint( ){cout<<"Destructor is called\n";}     //析构函数
    int getx(){return X;}       //有一个参数的get函数
    int gety(){return Y;}       //有一个参数的get函数
private:
    int X,Y,A;
};
TPoint::TPoint()
{
    cout<<"default constructor is clalled!\n";
};
TPoint::TPoint(TPoint &p)
{
    X=p.X;
    Y=p.Y;
    cout<<"Copy-initialization constructor is called\n";
    cout<<"Constructor is called\n";
};
TPoint::TPoint(int a)
{
    A=a;
    cout<<"constructor is called"<<A<<endl;
}
int main()
{
    TPoint p1(4,9);
    TPoint p2(p1);
    TPoint p3=p2;  //用对象P2初始化对象P3。
    TPoint p4,p5(2);
    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<<"constrcutor is called."<<i<<endl;
}
heapclass::heapclass()
{
    cout<<"default constructor is called."<<endl;
}
heapclass::~heapclass()
{
    cout<<"destructor 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中是三个指向类heapclass的对象指针,使用运算符new给他们赋值,同时对他们指向的对象进行初始化。
pa1= new heapclass(4); pa2= new heapclass; pa3= new heapclass(5);执行这三句分别调用了有参无参有参三次函数,输出结果前三句。
检查空间有足够的内存所以跳过if语句中的输出,而后输出exit main。最后使用运算符delete系统自动调用析构函数,输出最后三句。又使用运算符delete释放了这三个指针所指向的对象。

#include<iostream>
using namespace std;
class rectangle
{
public:
    rectangle(){len=0;wid=0;}  //wucan
    rectangle(double l,double w){len=l;wid=w;}
    double zc(){return 2*(len+wid);}
    double mj(){return len*wid;}
    double getl(){return len;}
    double getw(){return wid;}
    void print(double a,double b){len= a; wid=b;}
    printf()
    {
        cout<<"length:"<<len<<endl;
        cout<<"width:"<<wid<<endl;
    }
private:
    int len, wid;
};
int main()
{
    rectangle p1;
    rectangle p2(8.0,10.0);
    cout<<"p1的矩形尺寸:"<<endl;
    p1.printf();
    cout<<"p2的矩形尺寸:"<<endl;
    p2.printf();
    cout<<"p2的周长为:"<<p2.zc()<<endl;
    cout<<"p2的面积为:"<<p2.mj()<<endl;
    cout<<"p2的长度为:"<<p2.getl()<<endl;
    cout<<"p2的宽度为:"<<p2.getw()<<endl;
    p2.print(3.0,4.0);
    cout<<"修改后的矩形的尺寸:"<<endl;
    p2.printf();
    return 0;
}

输出结果:
这里写图片描述


分析与讨论

1、类中私有成员的访问权限;

  • 只有类中的函数才能访问类中私有成员。

2、构造函数和析构函数的调用顺序;

  • 在对象创建时,先用构造函数对其进行初始化,在程序结束后用析构函数释放由构造函数分配的内存,而且析构函数的执行顺序与构造函数的执行顺序刚好相反。

3、何时进行对象初始化?如何进行?(提示:注意分一般对象与堆对象讨论)

  • 一般对象:在对象的创建时对其进行初始化,可以用构造函数或者用拷贝构造函数进行初始化。
  • 堆对象:用new进行分配空间,再调用构造函数进行初始化。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!