c++中类和对象(中篇)包含《构造函数》,《析构函数》,《拷贝构造函数》,《赋值操作符的重载》等

本文详细解析C++中类的六大默认成员函数:构造函数、析构函数、拷贝构造函数、赋值操作符重载、const成员函数及取地址操作重载的功能与实现。通过代码示例,深入理解这些函数在对象生命周期中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学过之前的类和对象前篇之后,下来就学到了类的6个默认成员函数了,
《构造函数》,《析构函数》,《拷贝构造函数》,《赋值操作符的重载》,
《const成员函数》,《取地址及const取地址操作重载》,下来就一个一个看,

----》《构造函数》《-----

**构造函数:**是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有 一个合适的初始值,并且在对象的生命周期内只调用一次

特性
构造函数是特殊的成员函数,需要注意的是,构造函数的虽然名称叫构造,但是需要注意的是构造函数的主
要任务并不是开空间创建对象,而是初始化对象。
其特征如下:

  1. 函数名与类名相同。
  2. 无返回值。
  3. 对象实例化时编译器自动调用对应的构造函数。
  4. 构造函数可以重载。

下来就看一看构造函数的代码:

#include<iostream>
using namespace std;

class Date
{
  public:
  Date(int year = 1998,int month = 1,int day = 1)
	  {
	        _year = year;
            _month = month;
            _day = day;
			cout <<_year<< "-" <<_month << "-"<< _day <<endl;
	  }
  void SetDate(int year = 2019, int month = 1 ,int day = 14)
      {
            _year = year;
            _month = month;
            _day = day;
      } 
       //2 计算机自己给出;
	  /*Date()
	  {
		    cout <<_year<< "-" <<_month << "-"<< _day <<endl;
	  }*/   //没有函数调用的时候就直接由计算机给出随机的地址值。
	    //3 用户自己定义;
	/*  Date()
	  {
	       _year = 2019;
		   _month = 1;
		   _day = 15;
		   cout <<_year<< "-" <<_month << "-"<< _day <<endl;
	  }*/
	  //4// 无参构造函数
         Date ()
        {}
        void Display()
     {
         cout <<_year<< "-" <<_month << "-"<< _day <<endl;
      }
  void Display()
     {
         cout <<_year<< "-" <<_month << "-"<< _day <<endl;
      }   
private:
      int _year;
      int _month;
      int _day;
};

int main()
{
	Date d1;      //当是第一种的时候,计算机就会自己调运之前预先写好的值,
	d1.SetDate();
	d1.Display();
    Date d2;
	d2.SetDate(2019,1,16); //当自己定义的时候,计算机首先会使用用户写值
	d2.Display();
    return 0;
}

先给出前面两段给出的运行程序;
在这里插入图片描述
当你运行前面两段代码的时候,就可深刻体会到了,计算的缺省参数,半缺省,全缺省,当自己不写和自己写了之间的差别;后面的2和 3,我就没有运行,可以自己去运行一下。前面的说的自己调运或者计算机调用程序的过程,这个过程其实很简单,没有什么复杂的过程。

----》《析构函数》《-----

与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成类的一些资源清理工作。
----> 特性 <----
析构函数是特殊的成员函数。
其特征如下:

  1. 析构函数名是在类名前加上字符 ~。
  2. 无参数无返回值。
  3. 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。

下面就看一下代码:下面就看一下代码:
//前面的和上面《析构函数的一样》
//这个"~"就是析构函数代表一样:

~Date()  
	  {
		  cout <<"~Date()"<<endl;
	  } 
int  main()
{
       Date d1;
	  Date d2(2019,1,15);
	  Date d3;
}

在这里插入图片描述
可以看出来:当我调运了三次函数,每次函数结束,系统会自动调用析构函数,所以析构函数也就调运了三次。

----》《拷贝构造函数》《----

<构造函数>:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。
----<特征>----
拷贝构造函数也是特殊的成员函数,其特征如下:

  1. 拷贝构造函数是构造函数的一个重载形式。
  2. 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。

下来我们就看一看代码:

Date(int year = 1998,int month = 1,int day = 1)
	    {
	        _year = year;
            _month = month;
            _day = day;
			 cout <<_year<< "-" <<_month << "-"<< _day <<endl;  //打印d1;
		 }
	  Date(const Date& d)    //拷贝构造函数的
	  {
	         _year = d._year;
             _month = d._month;
             _day = d._day;
			 cout <<_year<< "-" <<_month << "-"<< _day <<endl; //打印d2;
	}
int main()
{
      Date d1;
	  Date d2(d1);   //调用拷贝构造的方法
	  return 0;
}

下来我们就可以看一下运行的结果:
在这里插入图片描述
由结果可以看出,d2将第一的值,拷贝了过去。
下来我们就看一下接下来的;

——《赋值运算符重载》——

《运算符重载》
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

函数名字为:关键字operator后面接需要重载的运算符符号

函数原型:返回值类型 operator操作符(参数列表)

注意:

1.不能通过连接其他符号来创建新的操作符:比如operator@

2.重载操作符必须有一个类类型或者枚举类型的操作数

3.用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不 能改变其含义

4.作为类成员的重载函数时,其形参看起来比操作数数目少1成员函数的

5.操作符有一个默认的形参this,限定为第一个形参 .* 、:: 、sizeof 、?: 、. 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

下来我们看一下代码:

Date(int year = 1998 ,int month = 1 ,int day = 1)
	  {
	        _year = year;
            _month = month;
            _day = day;
			cout <<_year<< "-" <<_month << "-"<< _day <<endl;
	  }
	  bool operator==(const Date&d2)//在operator里面只能有一个定义;
	  {
	       return _year == d2._year
			   &&  _month == d2._month
			   &&  _day == d2._day;
	  }
int main()
{
	Date d1;
	//Date d(2019,1,15);
	Date d2(2019,1,16);
	cout<<(d1 == d2)<<endl; //这里也可以写成d1 == d2;
	return 0;
	}

看一下运行的程序;
在这里插入图片描述
这里可以看出,当我们比较两个日期是否相同,就可以用运算符的重载。

二 《赋值运算符重载》

直接看下面一段代码:

Date(int year = 1998 ,int month = 1 ,int day = 1)
	  {
	           _year = year;
              _month = month;
              _day = day;
			cout <<_year<< "-" <<_month << "-"<< _day <<endl;
	  }
	 /* bool operator==(const Date&d2)//在operator里面只能有一个定义;  //这里定义为第一段代码:
	  {
	       return _year == d2._year
			   &&  _month == d2._month
			   &&  _day == d2._day;
	  }*/
	  Date& operator=(const Date& d) //这里定义为第二段代码
	  {
	      if(this != &d)
		  {
		       _year == d._year
			   &&  _month == d._month
			   &&  _day == d._day;
			   cout <<_year<< "-" <<_month << "-"<< _day <<endl;
		  }
		  else
			  return *this;
	  }
int main()
{
    Date d1;
	Date d2(2019,1,21);
    // 这里d1调用的编译器生成operator=完成拷贝,d2和d1的值也是一样的。
     d1 = d2;
}

我们开看一下结果:
在这里插入图片描述
就这样,我们可以把一个日期拷贝给另外一个,直接考虑用的是赋值运算重载,提高效率。
赋值运算符主要有四点:

  1. 参数类型
  2. 返回值
  3. 检测是否自己给自己赋值
  4. 返回*this
  5. 一个类如果没有显式定义赋值运算符重载,编译器也会生成一个,完成对象按字节序的值拷贝。

——《const成员函数》——

将const修饰的类成员函数称之为const成员函数const修饰类成员函数,实际修饰该成员函数隐含的this指针表明在该成员函数中不能对类的任何成员进行修改。const修饰的成员函数,修饰的是我们的this指针,准确来说是修饰的this指向的对象

相当于修饰的是*this

这张图片来自比特科技有限公司:在这里插入图片描述
我们看一下下面这一段代码:
c

lass Date
{
public:
	   Date(int year = 1998,int month = 1,int day = 1)
    	  {
    	        _year = year;
                _month = month;
                _day = day;
    			//cout <<_year<< "-" <<_month << "-"<< _day <<endl;
    	  }
	   void Print()
	   {
	        cout <<_year<< "-" <<_month << "-"<< _day <<endl;
	   }

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

int main()
{
    Date d1;
	d1.Print();

    return 0;
}

让程序运行一下:在这里插入图片描述我们可以看到程序可以运行,但是下面我这样,

int main()
{
    const Date d1;
	 d1.Print();
      return 0;
}

程序会怎么样?
在这里插入图片描述
我们可以看到程序直接崩了。为什么?
我们可以知道,const修饰的常量不能被改变,那么我们用可以改变的常量去掉用它,那当然是崩了。如果我们还想去调用,该怎么办?

下来,我就说一说,看下面一段代码:

void Print()
	   {
	        cout <<_year<< "-" <<_month << "-"<< _day <<endl;
	   }

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

int main()
{
    const  Date d1;
	d1.Print();
    return 0;
}

看一下运行的结果;
在这里插入图片描述
可以看出程序可以执行,
我们也可以这样调用;

	   void Print() const
	   {
	        cout <<_year<< "-" <<_month << "-"<< _day <<endl;
	   }

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

int main()
{
    const  Date d1;
	 d1.Print();
	Date d2;
	d2.Print();
    return 0;
}

看一下结果:
在这里插入图片描述
为什么,d2没有,const也可以调用函数?
答:在这里我们要明白这样一个道理,const可以读取,但是不能被修改,但是我d2过去,既可以读也可以写,所以可以调用函数,比如说:我们有很大权限,可以缩小自己的权限,但是不能去放大自己的权限。

——《取地址及const取地址操作符重载》——

其实这个就没有什么用了,非要说用哪里,那就看下面一段代码:

	   void Print() const
	   {
	        cout <<_year<< "-" <<_month << "-"<< _day <<endl;
	   }
	   Date* operator&()
	   {
	     
            return this;
	   }
	   const Date* operator&() const
	   {
	       return this;
	   }

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

int main()
{
     const  Date d1;
	 d1.Print();
	 Date d2;
	 d2.Print();
     cout << &d1 <<endl;
	 cout << &d2 <<endl;
     return 0;
}

在这里插入图片描述
可以看到,我们都可以去const或者非const修饰的地址,如果我们不想比热容看到我们的地址,那么,我们可以看到以下的代码:
Date* operator&()
{

        //return this;
	   return nullptr;
   }
   const Date* operator&() const
   {
       //return this;
	   return nullptr;
   }

这样就可以看不到了。

总结一下:这两个默认成员函数一般不用重新定义 ,编译器默认会生成。这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比
如想让别人获取到指定的内容!

如果还没有明白,我推荐大家看一下他写的博客,我个人感觉写的很好,比我写的好,嘿嘿
https://blog.youkuaiyun.com/lihao21/article/details/8634876

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值