类和对象(二)第九章怎样使用类和对象

利用构造函数对类对象进行初始化

  • 不能在类声明中对数据成员进行初始化,因为类不是一个实体,是抽象的,不占存储空间,无处容纳数据。
  • 若类中所有成员都是公用的,则可以在定义对象时对数据成员进行初始化,例:
class Time
{
   public:
         hour;
         min;
         sec;
 };
Time t1={3,23,5};
  • 用构造函数初始化,在建立对象时会自动执行构造函数。例:
class Time
{
   public:
         Time()//类内定义成员构造函数,函数名与类名相同
           {
              hour=0;
              min=0;
              sec=0;
            }
    ...
    private:
          int hour;
          int min;
          int sec;
 };
class Time
{
   public:
         Time();
    ...
    private:
          int hour;
          int min;
          int sec;
 };
 Time::Time()//在类外定义构造函数,要加上类名和域限定符::
     {
          hour=0;
          min=0;
          sec=0;
     }
  • 构造函数没有返回值,因此也没有类型。
  • 构造函数不需也不能被用户调用。
  • 可以用一个类对象初始化另一个类对象。例:
Time t1;
Time t2=t1;
  • 若用户自己没有定义构造函数,则c++系统会自动生成一个构造函数,只是这个构造函数的函数体是空的,不执行初始化操作。
  • 带参数的构造函数:构造函数首部:构造函数名(类型1 形参1,形参2…) 定义对象:类名 对象名(实参1,实参2…);例:
class BOX
{   
   public:
       BOX(int,int,int);//声明带参数的构造函数
   private:
       int height;
       int weight;
       int length;
 };//此处有;
 BOX::BOX(int h,int w,int l)//在类外定义带参数的构造函数
 {  
     height=h;
     weight=w;
     length=l;
  }//此处无;
 int main()
 {
     BOX::box1(12,23,65);
     BOX::box2(45,87,45);
 }
  • 用参数初始化表对数据成员初始化,一般形式:类名::构造函数名([参数表])[:成员初始化表]){ [构造函数体]} 其中[]内可有可无,例:
BOX::BOX(int h,int w,int l):height(h),weight(w),length(l){}//函数体为空

若数据成员是数组,则应当在构造函数的函数体中用语句对其赋值,而不能在参数初始化表中对其初始化,例:

class Student
{
    public:
        Student(int n,char s,nam[]):num(n),sex(s)//定义构造函数
        { 
            strcpy(name,nam);//函数体
         }
     ...
  • 构造函数的重载:例:
class BOX
{   
   public:
       BOX(int h,int w,int l):height(h),weight(w),length(l){}//在类内定义有参的构造函数,用参数的初始化表对数据成员进行初始化
       BOX(int h):height(h){}
       BOX(int h,int l):height(h),length(l){}
   private:
       int height;
       int weight;
       int length;
 };
 BOX::BOX()//在类外定义无参构造函数BOX
 {  
     height=10;
     weight=20;
     length=15;
  }
 int main()
 {
     BOX::box1(12,23,65);建立对象box1,指定三个实参
     BOX::box2;//建立对象box2,不指定实参,注意不要写成BOX::box2();这里是没有()的
     BOX::box3(12);
     BOX::box4(12,45);
 }

在建立对象时不给出实参的构造函数成为默认构造函数,一个类只能有一个默认构造函数,若用户未定义构造函数,系统会自动提供一个默认构造函数。
一个类中可以包含多个构造函数。

  • 使用默认参数的构造函数:后遭函数中参数的值可以通过实参传递,也可以指定为某些默认值,即如果用户不指定实参值,则编译系统就使形参取默认值。例:
class BOX
{ 
   public:
      BOX(int h=10,int w=10,int l=10);//声明构造函数时指定默认参数
   ...
};
BOX::BOX(int h,int w,int l)//在定义函数时可以不指定默认参数
{
   height=h;
   weight=w;
   length=l;
}  
int main()
{
   BOX box1;
   BOX box2(15);
   BOX box3(15,30);
   BOX box4(15,30,20);
 }

其作用相当于好几个重载的构造函数,应当在声明构造函数时指定默认值,而不能只在定义构造函数时指定默认值。
使用默认参数的构造函数也是默认构造函数,因此定义了此类构造函数之后不能再定义其他默认构造函数。
一般不应同时使用构造函数的重载和有默认参数的构造函数。

析构函数

  • 析构函数与构造函数的作用相反,它的名字是类名的前面加一个~(位取反运算符),对象生命期结束时,会自动执行析构函数,即以中情况:
    ①在一个函数中定义了一个对象(假设为自动局部对象),当这个函数被调用结束时,对象应该释放,在对象释放前自动执行析构函数。
    ②静态(static)局部对象载函数调用结束时对象并不释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用static局部对象的析构函数。
    ③如果定义了一个全局的对象,则再程序的流程离开其作用域时(如main函数结束或调用exit函数时),调用该全局对象的析构函数。
    ④如果用new运算符动态地建立了一个对象,当用delete运算符释放该对象时,先调用该对象的析构函数。

  • 析构函数的作用并不是删除对象,而是再撤销对象占用的内存之前完成一些清理工作,使这部分内存可以被程序分配给新对象使用。

  • 析构函数不能被重载,一个类只能有一个析构函数。

  • 析构函数作用不仅限于释放资源,还可以被用来执行用户希望在最后以西使用对象之后所执行的任何操作,如输出有关信息等。

  • 若用户未定义析构函数,则编译系统会自动生成析构函数,但其实际上什么操作也不进行,只是徒有名称与形式。

  • 例:

class BOX
{ 
   public:
      BOX(int h=10,int w=10,int l=10);
      ~BOX()
      { cout<<"I LOVE CHINA!"<<height<<'\n';}
   private:
   ...
};
  • 对同一类存储类别的对象而言,先构造的后析构,但同时也要注意其生命周期对其调用析构函数的影响。
    对象数组初始化

  • 构造函数只有一个参数,Student stu[3]={60,70,80};

  • 构造函数有多个参数,最好不用上述初始化方式,容易产生歧义,但是若写成这样,则表示为每个对象元素传递一个实参,所有Student stu[3]={60,70,80,90};是错误的。

Student stu[3]={Student(1001,17,45},Student(1001,17,45},Student(1001,17,45}};

对象指针

  • 对象空间的起始地址就是对象的指针。
  • 定义:类名 * 对象指针名; 例:
Time *pt;
Time t;
pt=&t;
  • 访问对象/对象的成员
*pt //pt所指向的对象t
(*pt).hour;//等价于t.hour
pt->hour;//等价于t.hour
(*pt).get_time()//等价于t.get_time()
  • 指向对象数据成员的指针:与普通指针类似
int *p;
p=&t.hour;
  • 指向对象的指针:
Time *p;
Time t;
p=&t;
  • 指向普通函数的指针:类型名(*指针变量名)(参数表列)
void(*p)();//p是指向void型函数的指针变量
p=fun;//将fun函数的入口地址赋给指针变量p
(*p)();//调用fun函数
  • 指向函数的指针变量的类型必须与赋值号右侧函数的类型相匹配:①函数参数的类型和参数个数②函数返回值的类型③所属的类
  • 指向对象函数的指针:定义指向公用成员函数的一般形式:数据类型名 (类名::*指针变量名)(参数表列);是指针变量指向一个公用成员函数的一般形式为:指针变量名=&类名::成员函数名例:
void (Time::*p2)();//正确
void Time::*p2();//错误,()优先级高于*,因此这是返回值为void型指针的函数
p2=&Time::get_time;//是指针变量指向一个公用成员函数

成员函数的入口地址正确写法是 &类名::成员函数名

void (Time::*p2)();
p2=&Time::get_time;//正确
p2=&t1.get_time;//错误,t1为对象名而不是类名

前两行还可以写成这样:

void(Time::*p3)()=&Time::get_time;//定义指针变量时指定其指向
  • this指针:指向本类对象的指针,它的值时当前被调用的成员函数所在的对象的起始地址,例:当调用a.volume时,编译系统就把对象a的起始地址赋给this指针,volume函数计算heightwidthlength的值,实际上是执行(this->height) * (this->width) * (this->length)或((*this).height * (*this).width *(*this).length)注意 *this两边的()不能省,成员运算符 . 的优先级高于指针运算符 * 。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值