类和对象

类和对象
 

类的构成:

class 类名
{
public:
     公有数据成员;
     公有成员函数:
protected:
     保护数据成员;
     保护成员函数:
private:
     私有数据成员;
     私有成员函数:
};

类的声明由关键字class打头,后跟类名,花括号中是类体,最后以一个分号“;”结束。


构造函数

  1. 是一种特殊的成员函数,名字必须和类名相同,可以有参数,但不能有返回值(void也不行)。
  2. 作用是对对象进行初始化,如给成员变量赋初值。
  3. 如果定义类时没写构造函数,则编译器会生成一个默认的无参构造函数
    默认构造函数无参数,不做任何操作
  1.  如果定义了构造函数,则编译器不生成默认的无参数的构造函数。
  2.  对象生成时构造函数自动被调用。对象一旦生成,就再也不能在其上执行构造函数。
  3.  一个类可以有多个构造函数。
无参构造函数&带参构造函数

class Date
{
public:
    //无参的构造函数
     Date( )
     {
          cout<<"Date( )"<<endl;
     }

    //带参数的构造
     Date(int year, int month, int day)
          :_year(year)
          ,_month(month)
          ,_day(day)
     {
          cout<<"Date(int year, int month, int day)"<<endl;
     }

private:
     int _year;
     int _month;
     int _day;
};

void test()
{
     Date d1;   //默认无参构造函数被调用
     Date d2(2017,12,4);  //带参构造函数被调用
     Date d3( );  //使用无参构造函数创建对象时,不能使用“Date d3( ); ”,因为“Date d3( );”表示声明一个名为d3的普通函数,此函数的返回值示Date类型。
}
拷贝构造函数

拷贝构造函数是一种特殊的构造函数,其形参是本类对象的引用
拷贝构造函数的作用是在建立一个新对象时,使用一个已经存在的对象去初始化这个新对象。

拷贝构造函数的特点
(1)函数名与类名相同,没有返回值。
(2)只有一个参数,并且是同类对象的引用。
(3)每个类都必须有一个拷贝构造函数。(可以自定义拷贝构造函数,用于按照需要初始化新对象;如果没有定义类的拷贝构造函数,编译器会自动生成一个默认的拷贝构造函数,用于复制出与数据成员值完全相同的新对象)
class Date
{
private:
     int _year;
     int _month;
     int _day;
};

void test( )
{
    Date d1;  //调用缺省无参构造函数
    Date  d2(d1);  //调用缺省的拷贝构造函数,将d2初始化成和d1一样
}

如果定义了自己的拷贝构造函数,则默认的拷贝构造函数不存在。

class Date
{
public:
     Date( )
     { }

     Date(const Date& d)
   {
     cout<<"Date(const Date& d)"<<endl;
          _year = d._year;
          _month = d._month;
          _day = d._day;
  }
  
private:
     int _year;
     int _month;
     int _day;
};

void test( )
{
    Date d1;  //调用缺省无参构造函数
    Date  d2(d1);  //调用自己定义的拷贝构造函数
}
拷贝构造函数起作用的三种情况:

1.当用类的对象去初始化同类的另一个对象时。
Date d2(d1);
Date d2 = d1;  //初始化语句,并非赋值语句。

2.当函数的形参是类的对象,调用函数进行形参和实参结合时。

void Func(A a1)  //形参是类Date的对象a1
{  }

int main( )
{
   A a
   Func(a2); //调用Func时,实参a2是类Date的对象,将调用拷贝构造函数,初始化形参a1.
   return 0;
}

3.当函数的返回值是对象,函数执行完成返回调用者时。

A Func1()
{
     A a1(4);
     return a1;   //函数的返回值是对象
}

int main( )
{
     A a2;
     a2 = Func1();   //函数执行完成,返回调用者时,调用拷贝构造函数
     return 0;
}

在函数Func1( )内,执行语句“return a1;”时,将会调用拷贝构造函数将a1的值复制到一个匿名对象中,
这个匿名对象是编译系统在主程序中临时创建的。函数执行结束时对象a1消失,但临时对象会存在于语句
“a2 = Func( )”中。执行完这个语句后,临时对象的使命也就完成了,该临时对象便自动消失了。
析构函数
它执行与析构函数相反的操作,通常用于撤销对象时的一些清理任务,如释放分配给对象的内存空间等。
  1. 与构造函数名字相同,但它前面必须加一个波浪号(~)。
  2. 没有参数,也没有返回值,而且不能重载。因此,在一个类中只能有一个析构函数
  3. 当撤销对象时,编译系统会自动调用析构函数。
在以下情况中,当对象生命周期结束时,析构函数会被自动调用:
(1) 如果定义了一个全局对象,则在程序流程离开其作用域(如main( )函数结束或调用exit( )函数)时,调用该全局的析构函数。
(2)如果一个对象被定义在一个函数体内,则当这个函数被调用结束时,该对象应该释放,析构函数被自动调用。
(3)若一个对象是使用new运算符动态创建的,在使用delete运算符释放它时,delete会自动调用析构函数。
class Date
{
public:
    //析构函数
  ~Date( )
     {
          cout<<"~Date( )"<<endl;
     }
private:
     int _year;
     int _month;
     int _day;
};

如果在一个对象完成其操作之前需要做一些内部清理,则应显式地定义析构函数,已完成所需的操作。

class Student
{
public:
     Student(char* name, int id)
     {
          _name = new char[strlen(name)+1];
          strcpy(_name, name);
          _id = id;
     }
     //这时需要析构函数做清理工作
     ~Student()
     {
          delete []_name;
     }
private:
     char* _name;
     int _id;
};
赋值运算符的重载
  • 重载运算符以后,不能改变运算符的优先级/结合性/操作数个数。
  • 赋值运算符的重载是对一个已存在的对象进行拷贝赋值。
  • 5个C++不能重载的运算符:
   .*      ::     sizeof      ?:       .
类对象存储
       事实上,给对象赋值就是给对象的数据成员赋值,不同对象的存储单元中存放的数据值通常是不同的,而不同对象的函数代码是相同的,不论调用哪一个对象的成员函数,其实调用的是相同内容的代码。
       因此,每个对象的存储空间都只是该对象的数据成员所占用的存储空间,而不包括成员函数代码所占用的空间,函数代码式存储在对象空间之外的。每个对象都有属于自己的数据成员,但是所有的成员函数代码却合用一份

       每个对象的大小为类中所有成员变量的大小之和。  

自引用this指针
class A
{
public:
     A(int x)
     {
          _x = x;
     }
     void disp()
     {
          cout<<"x="<<_x<<endl;
     }
private:
     int _x;
};

int main()
{
     A a(1);
     A b(2);
     a.disp();
     b.disp();
     return 0;
}
运行结果:
不论是对象a还是对象b调用disp( )函数时都执行同一条语句 cout<<"x="<<_x<<endl; 那么,执行a.disp()时,成员函数disp()怎样知道现在输出的应该是对a的_x值的1呢?类似的b呢?

    C++为成员函数提供了一个名字为this的指针,这个指针称为自引用指针。每当创建一个对象时,系统就自动把this指针作为一个隐含的参数传给该函数。不同的对象调用同一个成员函数时,C++编译器将根据成员函数的this指针所指向的对象来确定应该调用哪一个对象的数据成员。
例如:当调用成员函数a.disp()时,编译系统就把对象a的起始地址赋给this指针,于是在成员函数引用数据成员时,就按照this的指向找到对象a的数据成员。相当于执行cout<<"_x="<<this->_x<<endl;由于当前的this指向对象a,因此cout<<"_x="<<a._x<<endl;

显示this指针的值:




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值