使用类和对象,构造函数,析构函数的使用

本文详细解释了C++中类对象的初始化过程,包括为何不能在类声明中初始化,如何使用构造函数对数据成员进行初始化,以及构造函数、析构函数的定义、使用和调用顺序。还介绍了带参数的构造函数、默认参数和析构函数的作用及其规则。
摘要由CSDN通过智能技术生成

类对象的初始化

需要对类对象进行初始化

 对类里面的值进行初始化:

class Time
{hour=0;
minute=0;// 不能在类声明中对数据初始化
sec=0;
};

原因:类不是实体,而是一种抽象类型,不占用内存空间,显然无处存放数据。

ps:如果一个类中所有的成员都是共用,则可以在定义对象时对成员进行初始化。

class Time
{public:
    hour;
    minute;
    sec;
};
Time t1={14,56,30};//将t1初始化为14,56,30

用构造函数实现数据成员的初始化

定义:构造函数时一种特殊的函数,不需要用户来调用它,而是在建立对象时自动执行。

使用:构造函数的名字必须与类名同名,而不能随意命名,以便编译系统能识别它,并把它作为构造函数处理。

构造函数不具有任何类型,不返回任何值。

#include <iostream>
using namespace std;
class Time
{public:
    Time()//声明Time类
        {hour=0;//定义构造函数,函数名与类名相同
        minute=0;//利用构造函数对类中的数据成员赋初值
        sec=0;
        }//如果不赋初值就直接定义函数Time();就行
    void set_time();//成员函数声明
    void show_time();
 private:
     int hour;
     int minute;
     int sec;
};
void Time::set_time()//定义成员函数,向数据成员赋新值
{cin>>hour;
cin>>minute;
cin>>sec;
}
void Time::show_time()//定义成员函数,输出数据成员的值
{
    cout<<hour<<":"<<minute<<":"<<sec<<end;
}
int mian()
{
    Time t1;//建立对象t1,同时调用构造函数t1.Time()
    t1.set_time();//对t1的数据成员赋新值
    t2.show_time();//显示t1的数据成员的值
    Time t2;//建立对象t2,同时调用构造函数t2.Time()
    t2.show_time();//显示t2的数据成员的值
    return 0;
}

            

从键盘输入t1的值,然后程序运行输出输入的t1的值。然后输出t2的在一开始定义的初始值。

注意:只有在调用构造函数Time时才执行这些赋值语句,对当前的对象中的数据成员。

在类外定义构造函数:

Time::Time()
{
hour=0;
mintue=0;
sec=0;
}

1、每建立一个对象,就调用一次构造函数。

2、构造函数没有返回值,它的作用只是对对象进行初始化。因此也不需要在定义构造函数时声明类型,这是它和一般函数的一个不同的点。

int Time
{........}//这是错误的。

void time()
{........}//这也是错误的

t1.Time();//这是错误的
//构造函数不需要用户调用,也不能被用户调用

下面的是正确可以使用的

Time t1;//建立一个对象t1,同时调用构造函数t1.Time()
Time t2=t1;//建立对象t2,并用t1初始化t2
//此时把对象t1的各数据成员的值复制到t2相应各成员,而不调用构造函数t2.Time()

用带参数的构造函数对不同对象初始化

采用带参的构造函数,在调用不同对象的构造函数时,从外面将不同的数据传递给构造函数以实现不同对象的初始化。

构造函数首部的格式一般为:

构造函数名(类型1 形参1,类型2 形参2......)

定义对象的一般格式为:

类名 对象名(实参1,实参2......);

eg:计算长方体的体积

#include<iostream>
using namespace std;
class Box//声明Box类
{
    public:
        Box(int,int,int);//声明带参数的构造函数:构造函数名(类型1形参1....)
        int volume();//上面形参可以省略只写类型
    private:
        int height;
        int weight;
        int length;
};
Box::Box (int n,int w,int len)//在类外定义带参数的构造函数
{height=h;
wight=w;
length=len;
}
int Box::volume()
{return(height*width*length);
}
int main()
{
Box box1(12,25,30);//建立对象box1,并指定box1的高,宽,长的值:类名 对象名(实参1,实参2....)
cout<<"the volume of box1 is"<<box1.volume()<<endl;
Box box2(15,30,21);
cout<<"the volume of box2 is"<<box2.volume()<<endl;
return 0;
}

在构造函数中用参数初始化表对数据成员初始化

参数初始化表来实现对数据成员的初始化。

这种方法不在函数体内对数据成员初始化,而是在函数首部实现。

Box::Box(int h,int w,int len):height(h),width(w),length(len){}

带有参数初始化表的构造函数的一般形式

类名::构造函数名([参数表]:[:成员初始化表]
{[构造函数体]}
//方括号内为可选项(可有可无)

如果数据成员时数组,则应当在构造函数的函数体中用语句对其赋值,而不能参数初始化表中对其初始化。

eg:

class Student
{
    public:
        Student(int n,char s,nam[]):num(n),sex(s)//定义构造函数
        {strcpy(name,nam);}//函数体
//把形参nam的各元素值通过strcpy函数复制到name数组中
    private:    
        int num;
        char sex;
        char name[20];
};
//可以这样定义对象stud1:
Student studl(10101,'m',"wang_li");

对构造函数进行重载

在一个类中可以对多个构造函数,这些构造函数有相同的名字,而参数的个数或参数类型不相同,这称为函数的重载。

eg:定义两个构造函数,其中一个有参数,一个无参数

#include<iostream>
using namespace std;
calss Box
{
    public:
        Box();
        Box(int h,int w,int len):heigth(h),width(w),length(len){}//定义一个有参构造函数,用参数的初始化对数据成员初始化
    int volume;
    private:
        int heigth;
        int width;
        int length;
};
Box::Box()//在类外定义无参构造函数
{
    heigth=10;
    width=10;
    length=10;
}
int Box::volume()
{
    return(heigth*width*length);
}
int main()
{
    Box box1;//建立对象box1,不指定实参
    cout<<"the volume of box1 is"<<box1.volume()<<endl;
    Box box2(15,30,25);//建立函数对象box2,指定3个对象
    cout<<"the volume of box2 is"<<box2.volume()<<endl;
    return 0;
}

在建立对象函数时不必给出实参的构造函数,就称为默认构造函数。无参构造函数属于默认构造函数,一个类只有一个默认构造函数。如果用户未定义构造函数,则系统会自动提供一个默认构造函数,但它的函数体是空的。

构造函数不能被用户显示调用。

Box box1;//建立对象的正确方式
Box box2();//建立对象的错误方式

构造函数可以用默认参数

构造函数中的参数的值既可以通过实参传递,也可以指定为某些默认值,如果用户不指定实参值,编译系统就使形参的值为默认值。

eg:使参数长、宽、高的默认值均为10。

#include<iostream>
using namespace std;
calss Box
{
    public:
        Box(int h=10,int w=10,int len=10);//在声明构造函数Box时指定默认参数
        int volume();
    private:
        int height;
        int width;
        int length;
};
Box::Box(int h,int w,int len)//在定义Box函数时可以不指定默认参数
{
    heigth=h;
    width=w;
    length=len;
}
int Box::volume()
{
    return(heigth*width*length);
}
int main()
{
    Box box1;//没有给定参数
    cout<<"the volume of box1 is<<box1.volume()<<endl;
    Box box2(15);//只给一个实参
    cout<<"the volume of box2 is<<box2.volume()<<endl;
    Box box3(15,30);//只给定两个实参
    cout<<"the volume of box3 is<<box3.volume()<<endl;
    Box box4(15,30,20);//给定三个实参
    cout<<"the volume of box4 is<<box4.volume()<<endl;
    return 0;
}

为了避免调用时的歧义性,如果同时定义了下面两个构造函数,是错误的。

Box();//声明一个无参的构造函数
Box(int=10,int=10,int=10);//声明一个全部参数都指定了默认值的构造函数
//在建立对象时,如果写成
Box box1;
//系统无法识别调用的时哪个构造函数,产生歧义,编译报错

一个类中定义了全部是默认参数的构造函数后,不能再定义重载构造函数。

Box (int=10,int=10,int=10);//指定全部为默认参数
Box();//声明无参的构造函数
Box(int,int);//声明两个有参的构造函数
//以上三个只能出现一个,不然默认参数系统会混乱不知道调用哪个

利用析构函数进行清理工作

析构函数是一个特殊的函数成员。

定义,形式:

在名字前面加一个“~”符号。(在c++中“~”是取反运算符,析构函数是与构造函数作用相反的函数)

当对象的生命周期结束时,会自动执行析构函数。

具体有以下四种情况:

1、在一个函数中定义了一个对象(假设是自动局部对象),当这个函数被调用结束时,对象应该被释放,在对象释放前自动执行析构函数。

2、静态(static)局部对象子啊函数调用结束时并不释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用static局部对象的析构函数。

3、如果定义了一个全局的对象,则在程序的流程离开其作用域时(如main函数结束或调用exit函数)时,调用该全局对象的析构函数。

4、如果用new运算符动态建立了一个对象,当用delete运算符释放该对象时,先调用该对象的析构函数。

析构函数不返回任何值,没有函数类型,也没有函数参数。由于没有函数参数,因此它不能被重载。一个类可以有多个构造函数,但是只有一个析构函数。

析构函数时在声明类的时候定义的,(在让系统完成任何工作都在定义的时候进行)如果用户没有定义析构函数,c++编译系统会自动生成一个析构函数,但是只是徒有析构函数的名和形式而已,实际上什么也不进行。

#include<iostream>
#include<string>
using namespace std;
class Student
{
    public:
    Student(int n,string nam,char s)//定义有参数的构造函数
    {
        num=n;
        name=nam;
        sex=s;
        cout<<"constructor called."<<endl;
    }
    ~Student()//定义析构函数
    {cout<<"Destrctor called"<<endl;}//输出指定信息
void display()
{
    cout<<"num:"<<num<<endl;
    cout<<"name:"<<name<<endl;
    cout<<"sex:"<<sex<<endl;
}
private:
    int num;
    char name[10];
    char sex;
};
int main()
{
    Student stud1(10010,"Wang_Li",'f');//定义对象stud1
    stud1.display();
    Student stud2(10011,"Zhang_fan",'m');//定义对象stud2
    stud2.display();
    return 0;
}
//析构函数后面指定的结果是显示在最后面的。


            

调用构造函数和析构函数的顺序

上面析构函数后面输出的结果是:

Destructor called.                (执行stud2的析构函数)

Destructor called.                (执行stud1的析构函数)

其中,最先调用的构造函数,其对应的(同一对象中的)析构函数最后被调用,而最后被调用的构造函数正好与调用构造函数的顺序相反。

先构造的后析构,后构造的先析构。相当于一个栈。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值